|
|
package ControllerOauth2
|
|
|
|
|
|
import (
|
|
|
"dsSso/Const"
|
|
|
"dsSso/Const/DefaultConst"
|
|
|
"dsSso/Controller/ControllerRecaptcha"
|
|
|
"dsSso/Dao/DaoBaseGlobal"
|
|
|
"dsSso/Model"
|
|
|
"dsSso/Service/ServiceJoinApp"
|
|
|
"dsSso/Service/ServiceLoginPerson"
|
|
|
"dsSso/Utils/AesUtil"
|
|
|
"dsSso/Utils/CommonUtil"
|
|
|
"dsSso/Utils/ConfigUtil"
|
|
|
"dsSso/Utils/ConvertUtil"
|
|
|
"dsSso/Utils/RedisStorage"
|
|
|
"dsSso/Utils/RedisUtil"
|
|
|
"dsSso/Utils/RsaUtil"
|
|
|
"dsSso/Utils/SsoUtil"
|
|
|
"encoding/base64"
|
|
|
"encoding/json"
|
|
|
"fmt"
|
|
|
"github.com/RangelReale/osin"
|
|
|
"github.com/dchest/captcha"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
"github.com/tidwall/gjson"
|
|
|
"io/ioutil"
|
|
|
"net/http"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
//模块的路由配置
|
|
|
func Routers(r *gin.RouterGroup) {
|
|
|
rr := r.Group("")
|
|
|
//列表
|
|
|
rr.GET("/authorize", authorizeGet)
|
|
|
//注册POST接口,用于验证
|
|
|
r.POST("/authorize", authorizePost)
|
|
|
//用于授权码换取access_token
|
|
|
r.POST("/access_token", accessToken)
|
|
|
//获取验证码
|
|
|
r.GET("/getCaptcha", getCaptcha)
|
|
|
//获取验证码图片
|
|
|
r.GET("/getCaptchaPng", getCaptchaPng)
|
|
|
//退出接口
|
|
|
r.GET("/logout", logout)
|
|
|
//清空登录限制
|
|
|
r.GET("/resetRemainCount", resetRemainCount)
|
|
|
//微信登录
|
|
|
r.POST("/wxLogin", wxLogin)
|
|
|
//检查OpenId
|
|
|
r.GET("/checkOpenId", checkOpenId)
|
|
|
//绑定用户
|
|
|
r.POST("/bindWxUser", bindWxUser)
|
|
|
//解除绑定
|
|
|
r.POST("/unBindWxUser", unBindWxUser)
|
|
|
//添加接入系统
|
|
|
r.POST("/AddClient", AddClient)
|
|
|
//删除接入系统
|
|
|
r.POST("/DelClient", DelClient)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// @Summary 获取验证码
|
|
|
// @Description 获取验证码(为了以后WEB服务器的集群扩展,将验证码保存到redis中,避免ip_hash)
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Success 200 {object} Model.Res
|
|
|
// @Router /oauth2/getCaptcha [get]
|
|
|
func getCaptcha(c *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
//自定义redis为存储器
|
|
|
captcha.SetCustomStore(&ControllerRecaptcha.RedisStoreBean)
|
|
|
|
|
|
d := struct {
|
|
|
CaptchaId string
|
|
|
}{
|
|
|
captcha.NewLen(4),
|
|
|
}
|
|
|
if d.CaptchaId != "" {
|
|
|
c.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Msg: "获取成功",
|
|
|
Data: d.CaptchaId,
|
|
|
})
|
|
|
} else {
|
|
|
c.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusInternalServerError,
|
|
|
Msg: "获取失败",
|
|
|
Items: nil,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// @Summary 获取验证码图片
|
|
|
// @Description 获取验证码图片
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param captchaId query string true "captchaId"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/getCaptchaPng [get]
|
|
|
// @X-LengthLimit [{"captchaId":"20,20"}]
|
|
|
func getCaptchaPng(c *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
ControllerRecaptcha.ServeHTTP(c.Writer, c.Request)
|
|
|
}
|
|
|
|
|
|
//写Cookie
|
|
|
func WriteCookie(context *gin.Context, identityId string, personId string, deviceId string) {
|
|
|
//1、生成加密串
|
|
|
r, _ := AesUtil.Encrypt([]byte(identityId + "_" + personId + "_" + deviceId + "_" + ConvertUtil.Int64ToString(CommonUtil.GetCurrentTimestamp())))
|
|
|
//2、转base64
|
|
|
encodeString := base64.RawURLEncoding.EncodeToString([]byte(r))
|
|
|
//3、写cookie
|
|
|
context.SetCookie(ConfigUtil.AccessToken, encodeString, 0, "/", "", false, true)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
功能:产生授权码
|
|
|
作者:黄海
|
|
|
时间:2020-03-13
|
|
|
*/
|
|
|
func generateAuthCode(context *gin.Context, identityId string, personId string, deviceId string, typeId string) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
//写cookie
|
|
|
WriteCookie(context, identityId, personId, deviceId)
|
|
|
//如果是统一认证管理员登录
|
|
|
if identityId == "0" && personId == "0" {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Items: "/sso/static/ssoSystemList.html",
|
|
|
})
|
|
|
return
|
|
|
} else {
|
|
|
//如果不是第三方系统跳转过来,而且还不是SSO管理员的情况下。
|
|
|
if context.PostForm("client_id") == "" && context.Query("client_id") == "" {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Msg: "不是第三方系统跳转过来,而且还不是SSO管理员",
|
|
|
Items: "/sso/static/Error.html",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
//否则的话,返回授权码
|
|
|
req := context.Request
|
|
|
resp := RedisStorage.OsinServer.NewResponse()
|
|
|
defer resp.Close()
|
|
|
if ar := RedisStorage.OsinServer.HandleAuthorizeRequest(resp, req); ar != nil {
|
|
|
//标识验证通过
|
|
|
ar.Authorized = true
|
|
|
ar.Expiration = 3600 * 2 //过期时间两小时
|
|
|
RedisStorage.OsinServer.FinishAuthorizeRequest(resp, req, ar)
|
|
|
//用redis记录一下code--->personinfo的关系(黄海)
|
|
|
personStr := "{\"identity_id\":\"" + identityId + "\",\"person_id\":\"" + personId + "\",\"device_id\":\"" + deviceId + "\"}"
|
|
|
key := ConfigUtil.OAuth2RedisKeyPrefix + ":code_vs_person:" + resp.Output["code"].(string)
|
|
|
RedisUtil.SET(key, personStr, 10*60*time.Second)
|
|
|
}
|
|
|
//返回数据
|
|
|
url := resp.URL
|
|
|
code := resp.Output["code"].(string)
|
|
|
state := resp.Output["state"].(string)
|
|
|
//第三方的回调页面地址
|
|
|
oauthCallback := context.PostForm("oauth_callback")
|
|
|
if oauthCallback == "" {
|
|
|
oauthCallback = context.Query("oauth_callback")
|
|
|
}
|
|
|
//POST方式返回json数据
|
|
|
url = url + "?code=" + code + "&state=" + state + "&oauth_callback=" + oauthCallback
|
|
|
if typeId == "POST" {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Items: url,
|
|
|
})
|
|
|
return
|
|
|
} else { //GET方式跳转回客户端的回调页
|
|
|
context.Redirect(302, url)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// @Summary 获取access_token
|
|
|
// @Description 获取access_token
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param code query string false "code"
|
|
|
// @Param refresh_token query string false "refresh_token"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/access_token [post]
|
|
|
func accessToken(context *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
req := context.Request
|
|
|
resp := RedisStorage.OsinServer.NewResponse()
|
|
|
defer resp.Close()
|
|
|
var identityId string
|
|
|
var personId string
|
|
|
var deviceId string
|
|
|
//授权码
|
|
|
code := context.PostForm("code")
|
|
|
if code != "" {
|
|
|
//从redis中获取回来
|
|
|
personInfo, err := RedisUtil.GET(ConfigUtil.OAuth2RedisKeyPrefix + ":code_vs_person:" + code)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "输入的授权码不正确或已过期!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
//还原结构体
|
|
|
m := make(map[string]interface{})
|
|
|
json.Unmarshal([]byte(personInfo), &m)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "还原人员信息结构体失败!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
identityId, _ = m["identity_id"].(string)
|
|
|
personId, _ = m["person_id"].(string)
|
|
|
deviceId, _ = m["device_id"].(string)
|
|
|
if ar := RedisStorage.OsinServer.HandleAccessRequest(resp, req); ar != nil {
|
|
|
ar.Authorized = true
|
|
|
ar.Expiration = 3600 * 2
|
|
|
RedisStorage.OsinServer.FinishAccessRequest(resp, req, ar)
|
|
|
}
|
|
|
//2020-08-04
|
|
|
if resp.Output["access_token"] == nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "输入的授权码与其它相应的信息不匹配!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
//自己动手,丰衣足食
|
|
|
accessToken := resp.Output["access_token"].(string)
|
|
|
expiresIn := resp.Output["expires_in"].(int32)
|
|
|
refreshToken := resp.Output["refresh_token"].(string)
|
|
|
tokenType := resp.Output["token_type"].(string)
|
|
|
identityIdInt, _ := strconv.Atoi(identityId)
|
|
|
//记录refresh_token与identity_id,person_id关系
|
|
|
personStr := "{\"identity_id\":\"" + identityId + "\",\"person_id\":\"" + personId + "\",\"device_id\":\"" + deviceId + "\"}"
|
|
|
k := ConfigUtil.OAuth2RedisKeyPrefix + ":refresh_token_vs_person:" + refreshToken
|
|
|
RedisUtil.SET(k, personStr, time.Hour*24*30) //30天的有效期
|
|
|
|
|
|
//返回json数据
|
|
|
context.JSON(http.StatusOK,
|
|
|
gin.H{
|
|
|
"access_token": accessToken, "expires_in": expiresIn, "refresh_token": refreshToken,
|
|
|
"token_type": tokenType, "identity_id": identityIdInt, "person_id": personId, "code": 200})
|
|
|
return
|
|
|
} else {
|
|
|
//刷新token
|
|
|
clientRefreshToken := context.PostForm("refresh_token")
|
|
|
if clientRefreshToken != "" {
|
|
|
key := ConfigUtil.OAuth2RedisKeyPrefix + ":refresh_token_vs_person:" + clientRefreshToken
|
|
|
personInfo, err := RedisUtil.GET(key)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "输入的刷新token不正确!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
//还原结构体
|
|
|
m := make(map[string]interface{})
|
|
|
json.Unmarshal([]byte(personInfo), &m)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "还原人员信息结构体失败!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
identityId, _ = m["identity_id"].(string)
|
|
|
personId, _ = m["person_id"].(string)
|
|
|
if ar := RedisStorage.OsinServer.HandleAccessRequest(resp, req); ar != nil {
|
|
|
ar.Authorized = true
|
|
|
RedisStorage.OsinServer.FinishAccessRequest(resp, req, ar)
|
|
|
}
|
|
|
accessToken := resp.Output["access_token"].(string)
|
|
|
expiresIn := resp.Output["expires_in"].(int32)
|
|
|
refreshToken := resp.Output["refresh_token"].(string)
|
|
|
tokenType := resp.Output["token_type"].(string)
|
|
|
identityIdInt, _ := strconv.Atoi(identityId)
|
|
|
personIdInt, _ := strconv.Atoi(personId)
|
|
|
//删除旧的refresh_token
|
|
|
RedisUtil.DEL(key)
|
|
|
//返回json数据
|
|
|
context.JSON(http.StatusOK,
|
|
|
gin.H{
|
|
|
"access_token": accessToken, "expires_in": expiresIn, "refresh_token": refreshToken,
|
|
|
"token_type": tokenType, "identity_id": identityIdInt, "person_id": personIdInt, "code": 200})
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// @Summary 验证post
|
|
|
// @Description 验证post
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param captchaId formData string true "验证码id"
|
|
|
// @Param value formData string true "验证码值"
|
|
|
// @Param username formData string true "用户名"
|
|
|
// @Param password formData string true "密码"
|
|
|
// @Param device_id formData string true "设备ID"
|
|
|
// @Param redirect_uri formData string false "第三方系统的接口回调地址"
|
|
|
// @Param client_id formData string false "第三方系统的ID"
|
|
|
// #Param oauth_callback formData string false "第三方系统的回调页面地址"
|
|
|
// @Success 200 {object} Model.Res
|
|
|
// @Router /oauth2/authorize [post]
|
|
|
// @X-IntLimit ["device_id"]
|
|
|
// @X-EmptyLimit ["username","password","captchaId","value"]
|
|
|
func authorizePost(context *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
var identityId string
|
|
|
var personId string
|
|
|
var success bool
|
|
|
var remainCount int
|
|
|
//1、验证码
|
|
|
captchaId := context.PostForm("captchaId")
|
|
|
value := context.PostForm("value")
|
|
|
//2、用户名和密码
|
|
|
username := context.PostForm("username")
|
|
|
encryptPwd := context.PostForm("password")
|
|
|
//3、设备号
|
|
|
deviceId := context.PostForm("device_id")
|
|
|
//4、校验函数根据redis的读取结果进行检查
|
|
|
var redisStore ControllerRecaptcha.RedisStore
|
|
|
if redisStore.VerifyString(captchaId, value) {
|
|
|
//对前端AES加密过的密码进行解密
|
|
|
b, err := base64.StdEncoding.DecodeString(encryptPwd)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "密码不是系统允许的base64方式!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
decryptPwd, err := RsaUtil.RsaDecrypt(b)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "密码不是系统允许的加密方式!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
//调用service层的用户名和密码校验办法判断是不是允许登录
|
|
|
ip := context.ClientIP()
|
|
|
success, identityId, personId, _, remainCount, _ = ServiceLoginPerson.Login(username, string(decryptPwd), ip)
|
|
|
if !success {
|
|
|
//两次输入错误,不提醒
|
|
|
if remainCount >= 4 {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "用户名密码不正确或已禁用!",
|
|
|
})
|
|
|
} else if remainCount > 0 {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "用户名密码不正确或已禁用!您还可以尝试" + CommonUtil.ConvertIntToString(remainCount-1) + "次,超出次数限制后,账号将被禁用2小时!",
|
|
|
})
|
|
|
} else {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "账号已处于禁用状态,请稍后再试!",
|
|
|
})
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
} else {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "验证码不正确!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
//验证通过的话,返回授权码
|
|
|
generateAuthCode(context, identityId, personId, deviceId, "POST")
|
|
|
}
|
|
|
|
|
|
// @Summary 登录验证跳转路由
|
|
|
// @Description 登录验证跳转路由
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param client_id query string true "client_id"
|
|
|
// @Param redirect_uri query string true "redirect_uri"
|
|
|
// @Param device_id query string true "device_id"
|
|
|
// @Param oauth_callback query string true "第三方系统回跳的页面地址"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/authorize [get]
|
|
|
// @X-EmptyLimit ["client_id","redirect_uri","device_id","oauth_callback"]
|
|
|
func authorizeGet(context *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
//客户端的client_id
|
|
|
var paraClientId = context.Query("client_id")
|
|
|
//回调接口地址
|
|
|
var redirectUri = context.Query("redirect_uri")
|
|
|
//回调的页面地址
|
|
|
var oauthCallback = context.Query("oauth_callback")
|
|
|
//oauth_callback的base64检查
|
|
|
_, err := base64.StdEncoding.DecodeString(oauthCallback)
|
|
|
if err != nil {
|
|
|
msg := "传入的oauth_callback不不是经过标准码的base64字符串!"
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": false, "msg": msg})
|
|
|
return
|
|
|
}
|
|
|
//检查这个client_id是不是经过授权?
|
|
|
client, err := RedisStorage.OAuth2RedisStorage.GetClient(paraClientId)
|
|
|
if err != nil || client == nil {
|
|
|
msg := "传入的client_id不在系统的允许范围内!"
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": false, "msg": msg})
|
|
|
return
|
|
|
}
|
|
|
var sysUrl = client.GetRedirectUri()
|
|
|
if strings.Index(sysUrl, redirectUri) < 0 {
|
|
|
msg := "回调地址与系统中保存的不一致!"
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": false, "msg": msg})
|
|
|
return
|
|
|
}
|
|
|
var deviceId = context.Query("device_id")
|
|
|
//注册验证是否登录的接口,这个GET接口是直接跳转走的
|
|
|
//此处判断人员是否存在本站下的session,如果有的话
|
|
|
var identityId = DefaultConst.IdentityId
|
|
|
var personId = DefaultConst.PersonId
|
|
|
SsoSessionId := SsoUtil.ReadSsoCookie(context)
|
|
|
if SsoSessionId != "" {
|
|
|
//取出UserData
|
|
|
identityId, personId, _ = SsoUtil.AnalyzeSessionId(SsoSessionId)
|
|
|
if identityId != "" && personId != "" {
|
|
|
//为其生成授权码,并返回给客户端系统
|
|
|
generateAuthCode(context, identityId, personId, deviceId, "GET")
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
//如果没有本domain下的cookie,那么跳转到登录页
|
|
|
url := "/sso/static/index.html?redirect_uri=" + redirectUri + "&response_type=code&client_id=" + paraClientId + "&oauth_callback=" + oauthCallback
|
|
|
context.Redirect(302, url)
|
|
|
}
|
|
|
|
|
|
// @Summary 退出统一认证
|
|
|
// @Description 退出统一认证
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Param redirect_uri query string true "redirect_uri"
|
|
|
// @Produce json
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/logout [get]
|
|
|
func logout(context *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
//取出现在的cookie中的accessToken
|
|
|
accessToken := SsoUtil.ReadSsoCookie(context)
|
|
|
//获取所有接入系统的
|
|
|
list, _ := ServiceJoinApp.GetAppBaseList(1, Const.Int32Max, "")
|
|
|
for i := range list {
|
|
|
//每个系统的退出地址
|
|
|
logoutUri := list[i]["logout_uri"].(string)
|
|
|
//如果注册了退出地址的话
|
|
|
if len(logoutUri) > 0 {
|
|
|
//开启协程进行调用
|
|
|
go func() {
|
|
|
resp, err := http.Get(logoutUri + "?access_token=" + accessToken)
|
|
|
if err != nil {
|
|
|
fmt.Println(err)
|
|
|
return
|
|
|
}
|
|
|
defer resp.Body.Close()
|
|
|
body, _ := ioutil.ReadAll(resp.Body)
|
|
|
fmt.Println(string(body))
|
|
|
}()
|
|
|
}
|
|
|
}
|
|
|
//清除cookie
|
|
|
SsoUtil.DeleteSsoCookie(context)
|
|
|
|
|
|
//判断来源是内网还是外网,是指客户端的IP地址,即浏览器的IP
|
|
|
ipStart := strings.Split(context.Request.Host, ".")[0]
|
|
|
isIntranetIP := strings.Index("10,192,172", ipStart)
|
|
|
//外网
|
|
|
var s string
|
|
|
if isIntranetIP < 0 {
|
|
|
s = "defaultIndexWwUrl"
|
|
|
} else { //内网
|
|
|
s = "defaultIndexNwUrl"
|
|
|
}
|
|
|
//跳转回去,系统默认统一的回调首页
|
|
|
list, err := DaoBaseGlobal.GetGlobalInfoByValue(s)
|
|
|
if err != nil || len(list) == 0 {
|
|
|
msg := "获取全局变量defaultIndexUrl失败!"
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": false, "msg": msg})
|
|
|
return
|
|
|
}
|
|
|
globalValue := list[0]["global_value"].(string)
|
|
|
context.Redirect(302, globalValue)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// @Summary 重置错误重试次数限制
|
|
|
// @Description 重置错误重试次数限制
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param userName query string true "登录用的用户名"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/resetRemainCount [get]
|
|
|
// @X-EmptyLimit ["userName"]
|
|
|
func resetRemainCount(context *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
userName := context.Query("userName")
|
|
|
RedisUtil.DEL(Const.RemainCountRedisPrefix + userName)
|
|
|
msg := "成功清除禁用标识!"
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": true, "msg": msg})
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// @Summary 微信登录
|
|
|
// @Description 微信登录
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param code formData string true "腾讯返回的code码"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/wxLogin [post]
|
|
|
// @X-EmptyLimit ["code"]
|
|
|
func wxLogin(context *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
var code = context.PostForm("code")
|
|
|
//对接微信,腾讯给的AK+SK
|
|
|
appId := "wx3e0449144386938a"
|
|
|
appSecret := "5175be38ddd689d1621df35cc22c192b"
|
|
|
//验证的地址
|
|
|
var accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token"
|
|
|
var accessTokenParams = fmt.Sprintf("appid=%s&secret=%s&code=%s&grant_type=authorization_code", appId, appSecret, code)
|
|
|
//http调用
|
|
|
resp, err := http.Get(accessTokenUrl + "?" + accessTokenParams)
|
|
|
if err != nil {
|
|
|
fmt.Println(err)
|
|
|
return
|
|
|
}
|
|
|
defer resp.Body.Close()
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
if resp.StatusCode == 200 {
|
|
|
//将返回结果转为json
|
|
|
result := gjson.Get(string(body), "openid")
|
|
|
if len(result.Str) == 0 {
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": false, "openid": ""})
|
|
|
} else {
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": true, "openid": result.Str})
|
|
|
}
|
|
|
} else {
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": false, "openid": ""})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// @Summary 检查OPENID的是否已经绑定
|
|
|
// @Description 检查OPENID的是否已经绑定
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param openid query string true "OpenId"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/checkOpenId [get]
|
|
|
func checkOpenId(context *gin.Context) {
|
|
|
//异常处理
|
|
|
defer func() {
|
|
|
if err := recover(); err != nil {
|
|
|
fmt.Printf("%s\n", err)
|
|
|
}
|
|
|
}()
|
|
|
openId := context.Query("openid")
|
|
|
found, err, identityId, personId := ServiceLoginPerson.CheckOpenId(openId)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": false, "message": "检查OpenId失败!"})
|
|
|
return
|
|
|
}
|
|
|
//1、此OpenId已经存在挂接关系,那么写入相应的登录标识,并跳转到指定的页面
|
|
|
if found {
|
|
|
//写cookie
|
|
|
WriteCookie(context, CommonUtil.ConvertInt64ToString(identityId), personId, "1")
|
|
|
//4、跳转到XXX页面,比如集成页,或者管理员的首页
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": true, "openId": openId})
|
|
|
} else {
|
|
|
//2、如果此OpenId没有实现过挂接,应该跳转到绑定用户页面
|
|
|
context.JSON(http.StatusOK, map[string]interface{}{"success": false, "openId": openId})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// @Summary 绑定微信用户
|
|
|
// @Description 绑定微信用户
|
|
|
// @Tags 登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param username query string true "username"
|
|
|
// @Param password query string true "password"
|
|
|
// @Param openId query string true "openId"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/bindWxUser [get]
|
|
|
func bindWxUser(context *gin.Context) {
|
|
|
username := context.PostForm("username")
|
|
|
encryptPwd := context.PostForm("password")
|
|
|
openId := context.PostForm("openId")
|
|
|
//1、检查用户名与密码是不是匹配
|
|
|
ip := context.ClientIP()
|
|
|
b, err := base64.StdEncoding.DecodeString(encryptPwd)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "密码不是系统允许的base64方式!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
decryptPwd, err := RsaUtil.RsaDecrypt(b)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "密码不是系统允许的加密方式!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
//是否能登录
|
|
|
success, identityId, personId, _, remainCount, wxOpenId := ServiceLoginPerson.Login(username, string(decryptPwd), ip)
|
|
|
if remainCount == 0 {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "密码输入错误次数过多,请两个小时后继续登录!",
|
|
|
})
|
|
|
}
|
|
|
//2、如果匹配了,那么这个登录名是不是已经绑定过openId了
|
|
|
if success {
|
|
|
if len(wxOpenId) > 0 {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "此帐号已经绑定过微信号,无法再次绑定!如想修改微信号,请在个人中心通过修改!",
|
|
|
})
|
|
|
return
|
|
|
} else {
|
|
|
//3、进行两者之间的绑定
|
|
|
_, err := ServiceLoginPerson.BindWxUser(identityId, personId, openId)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "在执行BindWxUser函数时出错!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
//输出正确了~
|
|
|
//写cookie
|
|
|
WriteCookie(context, identityId, personId, "1")
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Msg: "绑定成功!",
|
|
|
})
|
|
|
}
|
|
|
} else {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "用户名密码错误,无法绑定!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// @Summary 解除绑定微信用户
|
|
|
// @Description 绑定微信用户
|
|
|
// @Tags 解除登录验证类
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/unBindWxUser [get]
|
|
|
func unBindWxUser(context *gin.Context) {
|
|
|
identityId, _ := context.Cookie("identity_id")
|
|
|
personId, _ := context.Cookie("person_id")
|
|
|
//进行两者之间的解除绑定
|
|
|
_, err := ServiceLoginPerson.UnBindWxUser(identityId, personId)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "在执行unBindWxUser函数时出错!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Msg: "解除绑定成功!",
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// @Summary 增加一个接入系统
|
|
|
// @Description 增加一个接入系统
|
|
|
// @Tags 统一认证管理
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param access_key formData string true "access_key"
|
|
|
// @Param secret_key formData string true "secret_key"
|
|
|
// @Param redirect_uri formData string true "redirect_uri"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/AddClient [post]
|
|
|
func AddClient(context *gin.Context) {
|
|
|
ip := context.ClientIP()
|
|
|
if ip != "127.0.0.1" {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "内部接口,只限本机进行调用!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
accessKey := context.PostForm("access_key")
|
|
|
secretKey := context.PostForm("secret_key")
|
|
|
redirectUri := context.PostForm("redirect_uri")
|
|
|
RedisStorage.OAuth2RedisStorage.CreateClient(
|
|
|
&osin.DefaultClient{
|
|
|
Id: accessKey,
|
|
|
Secret: secretKey,
|
|
|
RedirectUri: redirectUri,
|
|
|
},
|
|
|
)
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Msg: "增加成功!",
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// @Summary 删除一个接入系统
|
|
|
// @Description 删除一个接入系统
|
|
|
// @Tags 统一认证管理
|
|
|
// @Accept application/x-www-form-urlencoded
|
|
|
// @Produce json
|
|
|
// @Param access_key formData string true "access_key"
|
|
|
// @Success 200 {string} string
|
|
|
// @Router /oauth2/DelClient [post]
|
|
|
func DelClient(context *gin.Context) {
|
|
|
ip := context.ClientIP()
|
|
|
if ip != "127.0.0.1" {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusNotImplemented,
|
|
|
Msg: "内部接口,只限本机进行调用!",
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
accessKey := context.PostForm("access_key")
|
|
|
err := RedisStorage.OAuth2RedisStorage.DeleteClient(
|
|
|
&osin.DefaultClient{
|
|
|
Id: accessKey,
|
|
|
},
|
|
|
)
|
|
|
if err != nil {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Msg: "删除失败!" + err.Error(),
|
|
|
})
|
|
|
} else {
|
|
|
context.JSON(http.StatusOK, Model.Res{
|
|
|
Code: http.StatusOK,
|
|
|
Msg: "删除成功!",
|
|
|
})
|
|
|
}
|
|
|
}
|