You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

735 lines
23 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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/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)
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 formData string true "username"
// @Param password formData string true "password"
// @Param openId formData 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: "解除绑定成功!",
})
}