- first edition of auth2
This commit is contained in:
293
business/auth2/auth2.go
Normal file
293
business/auth2/auth2.go
Normal file
@@ -0,0 +1,293 @@
|
||||
package auth2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
UserIDEmpty = ""
|
||||
UserIDID = "userid"
|
||||
UserIDID2 = "userid2"
|
||||
UserIDMobile = "mobile"
|
||||
UserIDEmail = "email"
|
||||
)
|
||||
|
||||
const (
|
||||
TokenVer = "V2"
|
||||
TokenTypeSep = "."
|
||||
TokenUserEmpty = "NULL"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthTypeNone = ""
|
||||
AuthTypePassword = "password"
|
||||
AuthTypeEmail = "email"
|
||||
AuthTypeMobile = "mobile"
|
||||
)
|
||||
|
||||
const (
|
||||
DefTokenDuration = 7 * 24 * time.Hour // 7天
|
||||
)
|
||||
|
||||
type IUser interface {
|
||||
GetID() string // 这个ID是不可变的,系统内部使用的唯一标识
|
||||
GetID2() string // 这个是可改的,唯一的,用户设置的用户名
|
||||
GetMobile() string
|
||||
GetEmail() string
|
||||
GetName() string
|
||||
}
|
||||
|
||||
type IUserProvider interface {
|
||||
GetUser(authID, authIDType string) (user IUser)
|
||||
}
|
||||
|
||||
type IAuther interface {
|
||||
SendVerifyCode(authID string) (err error)
|
||||
// 负责验证secret,并找到相应的用户返回(password,email,mobile类型的不负责用户查找)如果找不到用户UserID为空
|
||||
VerifySecret(authID, authSecret string) (authBind *model.AuthBind, err error)
|
||||
AddAuthBind(authBind *model.AuthBind, userName string) (err error)
|
||||
UnbindAuth(authInfo *AuthInfo, authType string) (err error)
|
||||
Logout(authInfo *AuthInfo) (err error)
|
||||
}
|
||||
|
||||
var (
|
||||
authers map[string]IAuther
|
||||
userProvider IUserProvider
|
||||
authTypeGuesserMap = map[string]*regexp.Regexp{
|
||||
AuthTypeEmail: regexp.MustCompile(`^[A-Za-z0-9_\-\.]+\@[A-Za-z0-9_\-]+(\.[A-Za-z]+){1,5}$`),
|
||||
AuthTypeMobile: regexp.MustCompile(`^1[34578]\d{9}$`),
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInternalErrror = errors.New("内部错误")
|
||||
ErrTokenIsInvalid = errors.New("Token非法")
|
||||
ErrUserAlreadyExist = errors.New("用户已经存在")
|
||||
ErrUserNotExist = errors.New("用户不存在")
|
||||
ErrIllegalAuthType = errors.New("非法的登录类型")
|
||||
ErrIllegalAuthTypeAlreadyExist = errors.New("要登录类型已经存在")
|
||||
)
|
||||
|
||||
func init() {
|
||||
authers = make(map[string]IAuther)
|
||||
}
|
||||
|
||||
func Init(userProvider2 IUserProvider) {
|
||||
userProvider = userProvider2
|
||||
}
|
||||
|
||||
func RegisterAuther(authType string, handler IAuther) {
|
||||
authers[authType] = handler
|
||||
}
|
||||
|
||||
func CreateauthInfo(user IUser, authBindInfo *model.AuthBind, userData interface{}) (authInfo *AuthInfo) {
|
||||
token, tokenType := createToken(user)
|
||||
authInfo = &AuthInfo{
|
||||
IUser: user,
|
||||
AuthBindInfo: authBindInfo,
|
||||
|
||||
LoginTime: time.Now(),
|
||||
ExpiresIn: time.Now().Add(DefTokenDuration).Unix(),
|
||||
Token: token,
|
||||
TokenType: tokenType,
|
||||
UserData: userData,
|
||||
}
|
||||
if user != nil {
|
||||
globals.SugarLogger.Debugf("CreateauthInfo id:%s, id2:%s, authBindInfo:%s, authInfo:%s", authInfo.GetID(), authInfo.GetID2(), authInfo.GetMobile(), utils.Format4Output(authBindInfo, true), utils.Format4Output(authInfo, true))
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("CreateauthInfo authBindInfo:%s, authInfo:%s", utils.Format4Output(authBindInfo, true), utils.Format4Output(authInfo, true))
|
||||
}
|
||||
SetUserInfo(token, authInfo, DefTokenDuration)
|
||||
return authInfo
|
||||
}
|
||||
|
||||
// 账号密码时:authIDType可能是:UserIDID,UserIDID2,UserIDMobile,UserIDEmail,authSecret是密码的sha1
|
||||
// 邮箱时(如果允许):authIDType是:UserIDEmail,authSecret是验证码的sha1
|
||||
// 手机时(如果允许):authIDType是:UserIDMobile,authSecret是验证码的sha1
|
||||
// 公众号登录:authIDTypeD是UserIDEmpty,authSecret是code(这个函数是被微信的回调调用,不是直接被客户端调用)
|
||||
// 微信登录:authIDType是UserIDEmpty,authSecret是code(这个函数是被微信的回调调用,不是直接被客户端调用)
|
||||
// 小程序登录:authIDType是UserIDEmpty,authSecret是jsCode
|
||||
func Login(authType, authID, authIDType, authSecret string) (authInfo *AuthInfo, err error) {
|
||||
if handler := authers[authType]; handler != nil {
|
||||
var authBind *model.AuthBind
|
||||
var user IUser
|
||||
realauthID := authID
|
||||
if authIDType == AuthTypePassword {
|
||||
if user = userProvider.GetUser(authID, authIDType); user == nil {
|
||||
return nil, ErrUserNotExist
|
||||
}
|
||||
realauthID = user.GetID()
|
||||
}
|
||||
if authBind, err = handler.VerifySecret(realauthID, authSecret); err == nil {
|
||||
if authBind == nil { // mobile, email会返回nil(表示不会新建AuthBind实体)
|
||||
user = userProvider.GetUser(authID, authIDType)
|
||||
authBind = &model.AuthBind{
|
||||
Type: authType,
|
||||
AuthID: authID,
|
||||
Status: model.AuthBindStatusNormal,
|
||||
}
|
||||
} else {
|
||||
// 返回authBind中UserID为空表示只是认证,但本地没有记录,这种情况会返回临时TOKEN
|
||||
if authBind.UserID != "" {
|
||||
user = userProvider.GetUser(authBind.UserID, UserIDID)
|
||||
}
|
||||
}
|
||||
authInfo = CreateauthInfo(user, authBind, nil)
|
||||
}
|
||||
} else {
|
||||
err = ErrIllegalAuthType
|
||||
}
|
||||
return authInfo, err
|
||||
}
|
||||
|
||||
// 通过临时TOKEN绑定新创建的用户
|
||||
func BindUser(inauthInfo *AuthInfo, user IUser) (outauthInfo *AuthInfo, err error) {
|
||||
if inauthInfo == nil || user == nil {
|
||||
return nil, ErrInternalErrror
|
||||
}
|
||||
if inauthInfo.IUser != nil {
|
||||
return nil, ErrUserAlreadyExist
|
||||
}
|
||||
if handler := authers[inauthInfo.AuthBindInfo.Type]; handler != nil {
|
||||
inauthInfo.AuthBindInfo.UserID = user.GetID()
|
||||
if err = handler.AddAuthBind(inauthInfo.AuthBindInfo, user.GetName()); err == nil {
|
||||
RemoveUserInfo(inauthInfo.Token)
|
||||
outauthInfo = CreateauthInfo(user, inauthInfo.AuthBindInfo, inauthInfo.UserData)
|
||||
}
|
||||
} else {
|
||||
err = ErrIllegalAuthType
|
||||
}
|
||||
return outauthInfo, err
|
||||
}
|
||||
|
||||
// 添加新绑定
|
||||
func AddAuthBind(authInfo *AuthInfo, newAuthInfo *AuthInfo) (err error) {
|
||||
if authInfo == nil || newAuthInfo == nil {
|
||||
return ErrInternalErrror
|
||||
}
|
||||
if newAuthInfo.IUser != nil {
|
||||
return ErrIllegalAuthTypeAlreadyExist
|
||||
}
|
||||
RemoveUserInfo(newAuthInfo.Token)
|
||||
newAuthInfo.AuthBindInfo.UserID = authInfo.GetID()
|
||||
err = authers[newAuthInfo.AuthBindInfo.Type].AddAuthBind(newAuthInfo.AuthBindInfo, authInfo.GetName())
|
||||
return err
|
||||
}
|
||||
|
||||
// func AddAuthBind(authInfo *AuthInfo, authType, authID, authIDType, authSecret string) (err error) {
|
||||
// if authInfo == nil {
|
||||
// return ErrInternalErrror
|
||||
// }
|
||||
// // 密码绑定直接绑定
|
||||
// if authType == AuthTypePassword {
|
||||
// err = authers[AuthTypePassword].AddAuthBind(&model.AuthBind{
|
||||
// UserID: authInfo.GetID(),
|
||||
// Type: AuthTypePassword,
|
||||
// AuthID: authInfo.GetID(),
|
||||
// Status: model.AuthBindStatusNormal,
|
||||
// }, authInfo.GetName())
|
||||
// } else {
|
||||
// tmpauthInfo, err := Login(authType, authID, authIDType, authSecret)
|
||||
// if err == nil {
|
||||
// RemoveUserInfo(tmpauthInfo.Token)
|
||||
// tmpauthInfo.AuthBindInfo.UserID = authInfo.GetID()
|
||||
// err = authers[authType].AddAuthBind(tmpauthInfo.AuthBindInfo, authInfo.GetName())
|
||||
// }
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
func UnbindAuth(authInfo *AuthInfo, authType string) (err error) {
|
||||
if handler := authers[authType]; handler != nil {
|
||||
err = handler.UnbindAuth(authInfo, authType)
|
||||
} else {
|
||||
err = ErrIllegalAuthType
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Logout(authInfo *AuthInfo) (err error) {
|
||||
globals.SugarLogger.Debugf("Logout authInfo:%s", utils.Format4Output(authInfo, true))
|
||||
if handler := authers[authInfo.AuthBindInfo.Type]; handler != nil {
|
||||
err = handler.Logout(authInfo)
|
||||
}
|
||||
RemoveUserInfo(authInfo.Token)
|
||||
return err
|
||||
}
|
||||
|
||||
func SendVerifyCode(authID string) (err error) {
|
||||
authType := GuessAuthTypeFromAuthID(authID)
|
||||
if handler := authers[authType]; handler == nil {
|
||||
return ErrIllegalAuthType
|
||||
} else {
|
||||
return handler.SendVerifyCode(authID)
|
||||
}
|
||||
}
|
||||
|
||||
// token缓存相关
|
||||
|
||||
func RemoveUserInfo(token string) {
|
||||
api.Cacher.Del(token)
|
||||
}
|
||||
|
||||
func GetUserInfo(token string) (authInfo *AuthInfo, err error) {
|
||||
authInfo = new(AuthInfo)
|
||||
if err = api.Cacher.GetAs(token, authInfo); err == nil {
|
||||
return authInfo, nil
|
||||
}
|
||||
return nil, ErrTokenIsInvalid
|
||||
}
|
||||
|
||||
func SetUserInfo(token string, authInfo *AuthInfo, duration time.Duration) {
|
||||
api.Cacher.Set(token, authInfo, DefTokenDuration)
|
||||
}
|
||||
|
||||
func createToken(user IUser) (token string, tokenType int) {
|
||||
userID := TokenUserEmpty
|
||||
tokenType = TokenTypeOnlyAuth
|
||||
if user != nil {
|
||||
userID = "[" + user.GetID2() + "]"
|
||||
tokenType = TokenTypeNormal
|
||||
}
|
||||
return strings.Join([]string{
|
||||
TokenVer,
|
||||
time.Now().Format("20060102-150405"),
|
||||
userID,
|
||||
userID,
|
||||
}, TokenTypeSep), tokenType
|
||||
}
|
||||
|
||||
func GetTokenType(token string) (tokenType int) {
|
||||
tokenType = TokenTypeNone
|
||||
if token != "" {
|
||||
tokenPartList := strings.Split(token, TokenTypeSep)
|
||||
if (len(tokenPartList) == 1) || (len(tokenPartList) == 4 && tokenPartList[2] != TokenUserEmpty) {
|
||||
tokenType = TokenTypeNormal
|
||||
} else {
|
||||
tokenType = TokenTypeOnlyAuth
|
||||
}
|
||||
}
|
||||
return tokenType
|
||||
}
|
||||
|
||||
func IsV2Token(token string) bool {
|
||||
tokenPartList := strings.Split(token, TokenTypeSep)
|
||||
return tokenPartList[0] == TokenVer
|
||||
}
|
||||
|
||||
func GuessAuthTypeFromAuthID(authID string) (authType string) {
|
||||
for k, v := range authTypeGuesserMap {
|
||||
if v.FindStringSubmatch(authID) != nil {
|
||||
return k
|
||||
}
|
||||
}
|
||||
return AuthTypeNone
|
||||
}
|
||||
32
business/auth2/auth_info.go
Normal file
32
business/auth2/auth_info.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package auth2
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
const (
|
||||
TokenTypeNone = 0
|
||||
TokenTypeNormal = 1
|
||||
TokenTypeOnlyAuth = 2
|
||||
)
|
||||
|
||||
type AuthInfo struct {
|
||||
IUser
|
||||
AuthBindInfo *model.AuthBind
|
||||
|
||||
LoginTime time.Time
|
||||
ExpiresIn int64
|
||||
Token string
|
||||
TokenType int // TOKEN类型,
|
||||
UserData interface{}
|
||||
}
|
||||
|
||||
func (a *AuthInfo) GetAuthID() string {
|
||||
return a.AuthBindInfo.AuthID
|
||||
}
|
||||
|
||||
func (a *AuthInfo) GetAuthType() string {
|
||||
return a.AuthBindInfo.Type
|
||||
}
|
||||
86
business/auth2/authprovider/mobile/mobile.go
Normal file
86
business/auth2/authprovider/mobile/mobile.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package mobile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/KenmyZhang/aliyun-communicate"
|
||||
)
|
||||
|
||||
const (
|
||||
DefVerifyCodeDuration = 5 * time.Minute
|
||||
TestMobile = "91112345678"
|
||||
TestVerifyCode = "123456"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthType = auth2.AuthTypeMobile
|
||||
)
|
||||
|
||||
var (
|
||||
ErrVerifyCodeIsWrong = errors.New("验证码错")
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
auth2.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObj *Auther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObj = new(Auther)
|
||||
auth2.RegisterAuther(AuthType, AutherObj)
|
||||
}
|
||||
|
||||
// 特殊接口
|
||||
func (a *Auther) SendVerifyCode(mobileNumber string) error {
|
||||
code := fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
globals.SugarLogger.Debugf("SendVerifyCode mobileNumber:%s, code:%s", mobileNumber, code)
|
||||
|
||||
smsClient := aliyunsmsclient.New("http://dysmsapi.aliyuncs.com/")
|
||||
_, err := smsClient.Execute(globals.AliKey, globals.AliSecret, mobileNumber, "京西菜市", "SMS_84655036", string(utils.MustMarshal(map[string]interface{}{
|
||||
"code": code,
|
||||
})))
|
||||
if err == nil {
|
||||
api.Cacher.Set(mobileNumber, code, DefVerifyCodeDuration)
|
||||
} else {
|
||||
globals.SugarLogger.Infof("SendVerifyCode mobileNumber:%s failed with error:%v", mobileNumber, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(mobileNumber, code string) (authBind *model.AuthBind, err error) {
|
||||
globals.SugarLogger.Debugf("VerifySecret mobileNumber:%s, code:%s", mobileNumber, code)
|
||||
|
||||
err = ErrVerifyCodeIsWrong
|
||||
if mobileNumber == TestMobile && code == TestVerifyCode {
|
||||
err = nil
|
||||
} else {
|
||||
if value := api.Cacher.Get(mobileNumber); value != nil {
|
||||
if code == value.(string) {
|
||||
api.Cacher.Del(mobileNumber)
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 此函数为空
|
||||
func (a *Auther) AddAuthBind(authBind *model.AuthBind, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// 此函数为空
|
||||
func (a *Auther) UnbindAuth(authInfo *auth2.AuthInfo, authType string) (err error) {
|
||||
return err
|
||||
}
|
||||
55
business/auth2/authprovider/password/password.go
Normal file
55
business/auth2/authprovider/password/password.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package password
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthType = auth2.AuthTypePassword
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
auth2.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
ErrUserAndPassNotMatch = errors.New("用户名密码不匹配")
|
||||
)
|
||||
|
||||
func init() {
|
||||
auth2.RegisterAuther(AuthType, new(Auther))
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(userID, passMD5 string) (authBind *model.AuthBind, err error) {
|
||||
if authBind, err = dao.GetAuthBind(nil, "", AuthType, userID, ""); err == nil {
|
||||
err = a.checkPassword(authBind, passMD5)
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
err = auth2.ErrUserNotExist
|
||||
}
|
||||
return authBind, err
|
||||
}
|
||||
|
||||
// 特殊接口
|
||||
func (a *Auther) ChangePassword(userID, oldPassMD5, newPassMD5 string) (err error) {
|
||||
var authBind *model.AuthBind
|
||||
if authBind, err = dao.GetAuthBind(nil, "", AuthType, userID, ""); err == nil {
|
||||
if err = a.checkPassword(authBind, oldPassMD5); err == nil || authBind.AuthSecret == "" {
|
||||
authBind.AuthSecret = newPassMD5
|
||||
_, err = dao.UpdateEntity(nil, authBind, "AuthSecret")
|
||||
}
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
err = auth2.ErrUserNotExist
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Auther) checkPassword(authBind *model.AuthBind, passMD5 string) (err error) {
|
||||
if authBind.AuthSecret != passMD5 {
|
||||
return ErrUserAndPassNotMatch
|
||||
}
|
||||
return nil
|
||||
}
|
||||
80
business/auth2/authprovider/weixin/weixin.go
Normal file
80
business/auth2/authprovider/weixin/weixin.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package weixin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthTypeWeixin = "weixin"
|
||||
AuthTypeMP = "weixinmp"
|
||||
AuthTypeMini = "weixinmini"
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
auth2.DefAuther
|
||||
authType string
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObjWX *Auther
|
||||
AutherObjMP *Auther
|
||||
)
|
||||
|
||||
var (
|
||||
ErrStateIsWrong = errors.New("登录state非法")
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObjWX = &Auther{
|
||||
authType: AuthTypeWeixin,
|
||||
}
|
||||
auth2.RegisterAuther(AuthTypeWeixin, AutherObjWX)
|
||||
|
||||
AutherObjMP = &Auther{
|
||||
authType: AuthTypeMP,
|
||||
}
|
||||
auth2.RegisterAuther(AuthTypeMP, AutherObjMP)
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(state, code string) (authBind *model.AuthBind, err error) {
|
||||
globals.SugarLogger.Debugf("weixin VerifySecret code:%s", code)
|
||||
if state == "" {
|
||||
token, err2 := api.WeixinAPI.SNSRetrieveToken(code)
|
||||
if err = err2; err == nil {
|
||||
wxUserinfo, err2 := api.WeixinAPI.SNSGetUserInfo(token.AccessToken, token.OpenID)
|
||||
if err = err2; err == nil {
|
||||
db := dao.GetDB()
|
||||
if authBind, err = dao.GetAuthBind(db, "", a.authType, wxUserinfo.OpenID, ""); dao.IsNoRowsError(err) {
|
||||
var authBindList []*model.AuthBind
|
||||
if wxUserinfo.UnionID != "" {
|
||||
if authBindList, err = dao.GetAuthBindsByWXUnionID(db, wxUserinfo.UnionID); err == nil && len(authBindList) > 0 {
|
||||
authBind = authBindList[0]
|
||||
authBind.Type = a.authType
|
||||
authBind.AuthID = wxUserinfo.OpenID
|
||||
authBind.DetailData = string(utils.MustMarshal(wxUserinfo))
|
||||
err = a.AddAuthBind(authBind, wxUserinfo.NickName)
|
||||
}
|
||||
}
|
||||
if err == nil && len(authBindList) == 0 {
|
||||
authBind = &model.AuthBind{
|
||||
Type: a.authType,
|
||||
AuthID: wxUserinfo.OpenID,
|
||||
AuthID2: wxUserinfo.UnionID,
|
||||
DetailData: string(utils.MustMarshal(wxUserinfo)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = ErrStateIsWrong
|
||||
}
|
||||
return authBind, err
|
||||
}
|
||||
76
business/auth2/authprovider/weixin/weixin_mini.go
Normal file
76
business/auth2/authprovider/weixin/weixin_mini.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package weixin
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type MiniAuther struct {
|
||||
auth2.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
ErrAuthTypeShouldBeMini = errors.New("当前操作要求是小程序登录方式")
|
||||
)
|
||||
|
||||
var (
|
||||
AutherObjMini *MiniAuther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObjMini = new(MiniAuther)
|
||||
auth2.RegisterAuther(AuthTypeMP, AutherObjMini)
|
||||
}
|
||||
|
||||
func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBind *model.AuthBind, err error) {
|
||||
globals.SugarLogger.Debugf("weixin mini VerifySecret jsCode:%s", jsCode)
|
||||
|
||||
sessionInfo, err := api.WeixinMiniAPI.SNSCode2Session(jsCode)
|
||||
if err == nil {
|
||||
db := dao.GetDB()
|
||||
if authBind, err = dao.GetAuthBind(db, "", AuthTypeMP, sessionInfo.OpenID, ""); dao.IsNoRowsError(err) {
|
||||
var authBindList []*model.AuthBind
|
||||
if sessionInfo.UnionID != "" {
|
||||
if authBindList, err = dao.GetAuthBindsByWXUnionID(db, sessionInfo.UnionID); err == nil && len(authBindList) > 0 {
|
||||
authBind = authBindList[0]
|
||||
authBind.Type = AuthTypeMP
|
||||
authBind.AuthID = sessionInfo.OpenID
|
||||
authBind.DetailData = string(utils.MustMarshal(sessionInfo))
|
||||
authBind.UserData = sessionInfo.SessionKey
|
||||
err = a.AddAuthBind(authBind, "admin")
|
||||
}
|
||||
}
|
||||
if err == nil && len(authBindList) == 0 {
|
||||
authBind = &model.AuthBind{
|
||||
Type: AuthTypeMP,
|
||||
AuthID: sessionInfo.OpenID,
|
||||
AuthID2: sessionInfo.UnionID,
|
||||
DetailData: string(utils.MustMarshal(sessionInfo)),
|
||||
UserData: sessionInfo.SessionKey,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return authBind, err
|
||||
}
|
||||
|
||||
// 特殊接口
|
||||
func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, encryptedData, iv string) (decryptedDataBase64 string, err error) {
|
||||
globals.SugarLogger.Debugf("weixin mini DecryptData encryptedData:%s, iv:%s", encryptedData, iv)
|
||||
if authInfo.AuthBindInfo.Type != AuthTypeMini {
|
||||
return "", ErrAuthTypeShouldBeMini
|
||||
}
|
||||
sessionKey := authInfo.AuthBindInfo.UserData.(string)
|
||||
decryptedData, err := api.WeixinMiniAPI.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(decryptedData), nil
|
||||
}
|
||||
37
business/auth2/defauther.go
Normal file
37
business/auth2/defauther.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package auth2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
type DefAuther struct {
|
||||
}
|
||||
|
||||
// 此函数为空
|
||||
func (a *DefAuther) AddAuthBind(authBind *model.AuthBind, userName string) (err error) {
|
||||
dao.WrapAddIDCULDEntity(authBind, userName)
|
||||
err = dao.CreateEntity(nil, authBind)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *DefAuther) UnbindAuth(authInfo *AuthInfo, authType string) (err error) {
|
||||
_, err = dao.DeleteEntityLogically(nil, &model.AuthBind{}, nil, authInfo.GetID(), map[string]interface{}{
|
||||
"UserID": authInfo.GetID(),
|
||||
"Type": authType,
|
||||
model.FieldDeletedAt: utils.DefaultTimeValue,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *DefAuther) SendVerifyCode(authID string) error {
|
||||
return errors.New("当前登录类型不支持此操作")
|
||||
}
|
||||
|
||||
// 此函数为空
|
||||
func (a *DefAuther) Logout(authInfo *AuthInfo) error {
|
||||
return nil
|
||||
}
|
||||
@@ -107,3 +107,11 @@ func ConvertErr2NoUser(err error, mobileNum string) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *LoginInfo) GetAuthID() string {
|
||||
return a.ID
|
||||
}
|
||||
|
||||
func (a *LoginInfo) GetAuthType() string {
|
||||
return a.LoginType
|
||||
}
|
||||
|
||||
@@ -179,14 +179,14 @@ func BindMobile2(openid, secret, mobileNum, verifyCode, nickname string) (loginI
|
||||
func (a *AutherMiniProgram) BindWeiXin(ctx *jxcontext.Context, code, nickName string) (err error) {
|
||||
globals.SugarLogger.Debugf("AutherMiniProgram BindWeiXin code:%s, nickName:%s", code, nickName)
|
||||
loginInfo := ctx.GetLoginInfo()
|
||||
if loginInfo == nil || loginInfo.LoginType != mobile.LoginType {
|
||||
if loginInfo == nil || loginInfo.GetAuthType() != mobile.LoginType {
|
||||
return fmt.Errorf("调用AutherMiniProgram BindWeiXin时,必须以手机验证方式登录")
|
||||
}
|
||||
sessionInfo, err := api.WeixinMiniAPI.SNSCode2Session(code)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dao.UpdateWeiXinUser(dao.GetDB(), loginInfo.ID, nickName, sessionInfo.UnionID, "", sessionInfo.OpenID)
|
||||
err = dao.UpdateWeiXinUser(dao.GetDB(), loginInfo.GetAuthID(), nickName, sessionInfo.UnionID, "", sessionInfo.OpenID)
|
||||
return auth.ConvertErr2NoUser(err, "")
|
||||
}
|
||||
|
||||
@@ -234,13 +234,13 @@ func (a *AutherMiniProgram) Login(mobileNum, code string) (userID, LoginType str
|
||||
|
||||
func (a *AutherMiniProgram) Logout(loginInfo *auth.LoginInfo) error {
|
||||
globals.SugarLogger.Debugf("AutherMiniProgram Logout openid:%s", utils.Format4Output(loginInfo, false))
|
||||
return api.Cacher.Del(composeSessionKeyCacheKey(loginInfo.ID))
|
||||
return api.Cacher.Del(composeSessionKeyCacheKey(loginInfo.GetAuthID()))
|
||||
}
|
||||
|
||||
func (a *AutherMiniProgram) DecryptData(ctx *jxcontext.Context, encryptedData, iv string) (decryptedDataBase64 string, err error) {
|
||||
globals.SugarLogger.Debugf("AutherMiniProgram DecryptData encryptedData:%s, iv:%s", encryptedData, iv)
|
||||
var sessionKey string
|
||||
if err = api.Cacher.GetAs(composeSessionKeyCacheKey(ctx.GetLoginInfo().ID), &sessionKey); err != nil {
|
||||
if err = api.Cacher.GetAs(composeSessionKeyCacheKey(ctx.GetLoginInfo().GetAuthID()), &sessionKey); err != nil {
|
||||
return "", err
|
||||
}
|
||||
decryptedData, err := api.WeixinMiniAPI.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
|
||||
|
||||
@@ -76,7 +76,7 @@ func GetSelfInfo(ctx *jxcontext.Context) (storeUserInfo *StoreUserInfo, err erro
|
||||
return nil, auth.ErrAPINeedRealLogin
|
||||
}
|
||||
|
||||
fieldName := LoginTypeFieldMap[loginInfo.LoginType]
|
||||
fieldName := LoginTypeFieldMap[loginInfo.GetAuthType()]
|
||||
if fieldName == "" {
|
||||
return nil, auth.ErrIllegalLoginType
|
||||
}
|
||||
@@ -90,7 +90,7 @@ func GetSelfInfo(ctx *jxcontext.Context) (storeUserInfo *StoreUserInfo, err erro
|
||||
GROUP BY 1,2,3,4,5,6,7;
|
||||
`, fieldName)
|
||||
storeUserInfo = new(StoreUserInfo)
|
||||
if err = dao.GetRow(nil, storeUserInfo, sql, loginInfo.ID); err == nil || err == orm.ErrNoRows { // todo
|
||||
if err = dao.GetRow(nil, storeUserInfo, sql, loginInfo.GetAuthID()); err == nil || err == orm.ErrNoRows { // todo
|
||||
err = nil
|
||||
if storeUserInfo.MembersStr != "" {
|
||||
err = utils.UnmarshalUseNumber([]byte(storeUserInfo.MembersStr), &storeUserInfo.Members)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package jxcontext
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/auth"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
@@ -12,11 +14,16 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
type IAuther interface {
|
||||
GetAuthID() string
|
||||
GetAuthType() string
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
rootTask tasksch.ITask
|
||||
token string
|
||||
accessUUID string
|
||||
userInfo *auth.LoginInfo
|
||||
userInfo IAuther //*auth.LoginInfo
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
mapData map[interface{}]interface{}
|
||||
@@ -56,7 +63,17 @@ func New(rootTask tasksch.ITask, token string, w http.ResponseWriter, r *http.Re
|
||||
mapData: make(map[interface{}]interface{}),
|
||||
accessUUID: utils.GetUUID(),
|
||||
}
|
||||
ctx.userInfo, err = auth.GetUserInfo(token)
|
||||
if auth2.IsV2Token(token) {
|
||||
authInfo, err2 := auth2.GetUserInfo(token)
|
||||
if err = err2; err == nil {
|
||||
ctx.userInfo = authInfo
|
||||
if authInfo.TokenType != auth2.TokenTypeNormal {
|
||||
err = errors.New("需要正式TOKEN")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ctx.userInfo, err = auth.GetUserInfo(token)
|
||||
}
|
||||
if err != nil && beego.BConfig.RunMode == "prod" {
|
||||
globals.SugarLogger.Debugf("token is invalid, token:%s", token)
|
||||
return nil, model.ErrCodeTokenIsInvalid, err
|
||||
@@ -67,7 +84,7 @@ func New(rootTask tasksch.ITask, token string, w http.ResponseWriter, r *http.Re
|
||||
func (ctx *Context) GetUserName() string {
|
||||
userName := ctx.token
|
||||
if ctx.userInfo != nil {
|
||||
userName = ctx.userInfo.ID
|
||||
userName = ctx.userInfo.GetAuthID()
|
||||
}
|
||||
if len(userName) > MaxUserNameLen {
|
||||
userName = userName[:MaxUserNameLen]
|
||||
@@ -77,7 +94,7 @@ func (ctx *Context) GetUserName() string {
|
||||
|
||||
func (ctx *Context) GetLoginID() string {
|
||||
if ctx.userInfo != nil {
|
||||
return ctx.userInfo.ID
|
||||
return ctx.userInfo.GetAuthID()
|
||||
}
|
||||
return ""
|
||||
|
||||
@@ -85,7 +102,7 @@ func (ctx *Context) GetLoginID() string {
|
||||
|
||||
func (ctx *Context) GetLoginType() string {
|
||||
if ctx.userInfo != nil {
|
||||
return ctx.userInfo.LoginType
|
||||
return ctx.userInfo.GetAuthType()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -98,7 +115,7 @@ func (ctx *Context) GetAccessUUID() string {
|
||||
return ctx.accessUUID
|
||||
}
|
||||
|
||||
func (ctx *Context) GetLoginInfo() *auth.LoginInfo {
|
||||
func (ctx *Context) GetLoginInfo() IAuther {
|
||||
return ctx.userInfo
|
||||
}
|
||||
|
||||
|
||||
30
business/model/auth2.go
Normal file
30
business/model/auth2.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package model
|
||||
|
||||
const (
|
||||
AuthBindStatusNormal = 1
|
||||
AuthBindStatusDisabled = 2
|
||||
)
|
||||
|
||||
type AuthBind struct {
|
||||
ModelIDCULD
|
||||
|
||||
UserID string `orm:"size(48);column(user_id)" json:"userID"`
|
||||
Type string `orm:"size(16)" json:"type"`
|
||||
Status int8 `json:"status"`
|
||||
|
||||
AuthID string `orm:"size(48);index" json:"authID"`
|
||||
AuthID2 string `orm:"size(48);index" json:"authID2"`
|
||||
AuthSecret string `orm:"size(48)" json:"authSecret"`
|
||||
AuthSecret2 string `orm:"size(48)" json:"authSecret2"`
|
||||
Remark string `orm:"size(255)" json:"remark"`
|
||||
DetailData string `orm:"type(text)" json:"-"`
|
||||
|
||||
UserData interface{} `orm:"-" json:"-"`
|
||||
}
|
||||
|
||||
func (*AuthBind) TableUnique() [][]string {
|
||||
return [][]string{
|
||||
[]string{"UserID", "Type", "DeletedAt"},
|
||||
[]string{"AuthID", "Type", "DeletedAt"},
|
||||
}
|
||||
}
|
||||
11
business/model/dao/dao_auth2.go
Normal file
11
business/model/dao/dao_auth2.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package dao
|
||||
|
||||
import "git.rosy.net.cn/jx-callback/business/model"
|
||||
|
||||
func GetAuthBind(db *DaoDB, userID, authType, authID, authID2 string) (authBind *model.AuthBind, err error) {
|
||||
return authBind, err
|
||||
}
|
||||
|
||||
func GetAuthBindsByWXUnionID(db *DaoDB, unionID string) (authBinds []*model.AuthBind, err error) {
|
||||
return authBinds, err
|
||||
}
|
||||
43
business/model/user.go
Normal file
43
business/model/user.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package model
|
||||
|
||||
type User struct {
|
||||
ModelIDCULD
|
||||
UserID string `orm:"size(48);column(user_id)" json:"userID"` // 内部唯一标识
|
||||
UserID2 string `orm:"size(48);column(user_id2)" json:"userID2"` // 外部唯一标识(一般用于登录)
|
||||
Name string `orm:"size(48)" json:"name"` // 外部唯一显示 标识(一般用于显示)
|
||||
Mobile string `orm:"size(32)" json:"mobile"`
|
||||
Email string `orm:"size(32)" json:"email"`
|
||||
Status int8 `json:"status"`
|
||||
IDCardNo string `orm:"size(18);column(id_card_no)" json:"idCardNo"` // 身份证号
|
||||
}
|
||||
|
||||
func (*User) TableUnique() [][]string {
|
||||
return [][]string{
|
||||
[]string{"UserID", "DeletedAt"},
|
||||
[]string{"UserID2", "DeletedAt"},
|
||||
[]string{"Name", "DeletedAt"},
|
||||
[]string{"Mobile", "DeletedAt"},
|
||||
[]string{"Email", "DeletedAt"},
|
||||
[]string{"IDCardNo", "DeletedAt"},
|
||||
}
|
||||
}
|
||||
|
||||
func (user *User) GetID() string {
|
||||
return user.UserID
|
||||
}
|
||||
|
||||
func (user *User) GetID2() string {
|
||||
return user.UserID2
|
||||
}
|
||||
|
||||
func (user *User) GetMobile() string {
|
||||
return user.Mobile
|
||||
}
|
||||
|
||||
func (user *User) GetEmail() string {
|
||||
return user.Email
|
||||
}
|
||||
|
||||
func (user *User) GetName() string {
|
||||
return user.Name
|
||||
}
|
||||
174
controllers/auth2.go
Normal file
174
controllers/auth2.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/auth"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNeedV2Token = errors.New("需要V2版的TOKEN")
|
||||
)
|
||||
|
||||
type Auth2Controller struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// @Title 发送验证码
|
||||
// @Description 发送验证码
|
||||
// @Param authID formData string true "手机号或邮件"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /SendVerifyCode [post]
|
||||
func (c *Auth2Controller) SendVerifyCode() {
|
||||
c.callSendVerifyCode(func(params *tAuth2SendVerifyCodeParams) (retVal interface{}, errCode string, err error) {
|
||||
err = auth2.SendVerifyCode(params.AuthID)
|
||||
return retVal, "", err
|
||||
})
|
||||
}
|
||||
|
||||
// @Title 登录接口
|
||||
// @Description 登录接口(微信与公众号登录不能直接调用此接口)
|
||||
// @Param authType formData string true "登录类型,当前支持[password:本地账号密码,mobile:手机短信,weixin:微信登录,weixinmp:微信公众号登录,weixinmini;小程序登录]"
|
||||
// @Param authSecret formData string true "不同登录类型的登录秘密"
|
||||
// @Param authID formData string false "登录ID,登录类型为password时依赖于authIDType,其它为相应登录类型的id"
|
||||
// @Param authIDType formData string false "只有在登录类型为password时,才有意义,分别为:userID2:用户名,email,mobile"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /Login [post]
|
||||
func (c *Auth2Controller) Login() {
|
||||
c.callLogin(func(params *tAuth2LoginParams) (retVal interface{}, errCode string, err error) {
|
||||
retVal, err = auth2.Login(params.AuthType, params.AuthID, params.AuthIDType, params.AuthSecret)
|
||||
return retVal, "", err
|
||||
})
|
||||
}
|
||||
|
||||
// @Title 微信认证回调接口
|
||||
// @Description 微信认证回调接口,自己不能直接调用
|
||||
// @Param code query string true "客户同意后得到的code"
|
||||
// @Param block query string true "回调地址"
|
||||
// @Param state query string false "微信回调的登录状态"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /WeixinOAuth2 [get]
|
||||
func (c *Auth2Controller) WeixinOAuth2() {
|
||||
var redirectURL string
|
||||
c.callWeixinOAuth2(func(params *tAuth2WeixinOAuth2Params) (retVal interface{}, errCode string, err error) {
|
||||
authInfo, err := auth2.Login(weixin.AuthTypeWeixin, params.State, "", params.Code)
|
||||
var callResult *CallResult
|
||||
if err == nil {
|
||||
callResult = &CallResult{
|
||||
Code: model.ErrCodeSuccess,
|
||||
Data: string(utils.MustMarshal(authInfo)),
|
||||
}
|
||||
} else {
|
||||
callResult = &CallResult{
|
||||
Code: model.ErrCodeGeneralFailed,
|
||||
Desc: err.Error(),
|
||||
}
|
||||
}
|
||||
redirectURL = fmt.Sprintf("%s?info=%s", params.Block, base64.StdEncoding.EncodeToString(utils.MustMarshal(callResult)))
|
||||
return retVal, model.ErrorCodeIgnore, err
|
||||
})
|
||||
c.Redirect(redirectURL, http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
// @Title 微信公众号认证回调接口
|
||||
// @Description 微信公众号认证回调接口,自己不能直接调用
|
||||
// @Param code query string true "客户同意后得到的code"
|
||||
// @Param block query string true "回调地址"
|
||||
// @Param state query string false "微信回调的登录状态"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /WeixinMPOAuth2 [get]
|
||||
func (c *Auth2Controller) WeixinMPOAuth2() {
|
||||
var redirectURL string
|
||||
c.callWeixinMPOAuth2(func(params *tAuth2WeixinMPOAuth2Params) (retVal interface{}, errCode string, err error) {
|
||||
authInfo, err := auth2.Login(weixin.AuthTypeMP, params.State, "", params.Code)
|
||||
var callResult *CallResult
|
||||
if err == nil {
|
||||
callResult = &CallResult{
|
||||
Code: model.ErrCodeSuccess,
|
||||
Data: string(utils.MustMarshal(authInfo)),
|
||||
}
|
||||
} else {
|
||||
callResult = &CallResult{
|
||||
Code: model.ErrCodeGeneralFailed,
|
||||
Desc: err.Error(),
|
||||
}
|
||||
}
|
||||
redirectURL = fmt.Sprintf("%s?info=%s", params.Block, base64.StdEncoding.EncodeToString(utils.MustMarshal(callResult)))
|
||||
return retVal, model.ErrorCodeIgnore, err
|
||||
})
|
||||
c.Redirect(redirectURL, http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
// @Title 登出接口
|
||||
// @Description 登出接口(此接口兼容V1的TOKEN)
|
||||
// @Param token header string true "认证token"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /Logout [delete]
|
||||
func (c *Auth2Controller) Logout() {
|
||||
c.callLogout(func(params *tAuth2LogoutParams) (retVal interface{}, errCode string, err error) {
|
||||
if authInfo, ok := params.Ctx.GetLoginInfo().(*auth2.AuthInfo); ok {
|
||||
err = auth2.Logout(authInfo)
|
||||
} else {
|
||||
err = auth.Logout(params.Token)
|
||||
}
|
||||
return nil, "", err
|
||||
})
|
||||
}
|
||||
|
||||
// @Title 绑定认证方式
|
||||
// @Description 绑定认证方式
|
||||
// @Param token header string true "认证token"
|
||||
// @Param authToken formData string true "之前通过login得到的新认证TOKEN"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /AddAuthBind [post]
|
||||
func (c *Auth2Controller) AddAuthBind() {
|
||||
c.callAddAuthBind(func(params *tAuth2AddAuthBindParams) (retVal interface{}, errCode string, err error) {
|
||||
authInfo, err2 := c.getAuth2Info(params.Ctx)
|
||||
if err := err2; err == nil {
|
||||
newAuthInfo, err2 := auth2.GetUserInfo(params.AuthToken)
|
||||
if err = err2; err == nil {
|
||||
err = auth2.AddAuthBind(authInfo, newAuthInfo)
|
||||
}
|
||||
}
|
||||
return retVal, "", err
|
||||
})
|
||||
}
|
||||
|
||||
// @Title 删除认证方式
|
||||
// @Description 删除认证方式
|
||||
// @Param token header string true "认证token"
|
||||
// @Param authType formData string true "登录类型,当前支持[weixin:微信登录,weixinmp:微信公众号登录,weixinmini;小程序登录]"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /RemoveAuthBind [post]
|
||||
func (c *Auth2Controller) RemoveAuthBind() {
|
||||
c.callRemoveAuthBind(func(params *tAuth2RemoveAuthBindParams) (retVal interface{}, errCode string, err error) {
|
||||
authInfo, err2 := c.getAuth2Info(params.Ctx)
|
||||
if err := err2; err == nil {
|
||||
err = auth2.UnbindAuth(authInfo, params.AuthType)
|
||||
}
|
||||
return retVal, "", err
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Auth2Controller) getAuth2Info(ctx *jxcontext.Context) (authInfo *auth2.AuthInfo, err error) {
|
||||
if authInfo, ok := ctx.GetLoginInfo().(*auth2.AuthInfo); ok {
|
||||
return authInfo, err
|
||||
}
|
||||
return nil, ErrNeedV2Token
|
||||
}
|
||||
@@ -7,6 +7,62 @@ import (
|
||||
|
||||
func init() {
|
||||
|
||||
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"],
|
||||
beego.ControllerComments{
|
||||
Method: "AddAuthBind",
|
||||
Router: `/AddAuthBind`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"],
|
||||
beego.ControllerComments{
|
||||
Method: "Login",
|
||||
Router: `/Login`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"],
|
||||
beego.ControllerComments{
|
||||
Method: "Logout",
|
||||
Router: `/Logout`,
|
||||
AllowHTTPMethods: []string{"delete"},
|
||||
MethodParams: param.Make(),
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"],
|
||||
beego.ControllerComments{
|
||||
Method: "RemoveAuthBind",
|
||||
Router: `/RemoveAuthBind`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"],
|
||||
beego.ControllerComments{
|
||||
Method: "SendVerifyCode",
|
||||
Router: `/SendVerifyCode`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"],
|
||||
beego.ControllerComments{
|
||||
Method: "WeixinMPOAuth2",
|
||||
Router: `/WeixinMPOAuth2`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"],
|
||||
beego.ControllerComments{
|
||||
Method: "WeixinOAuth2",
|
||||
Router: `/WeixinOAuth2`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:AuthController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:AuthController"],
|
||||
beego.ControllerComments{
|
||||
Method: "BindMiniProgram",
|
||||
|
||||
@@ -81,6 +81,11 @@ func init() {
|
||||
&controllers.MsgController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/auth2",
|
||||
beego.NSInclude(
|
||||
&controllers.Auth2Controller{},
|
||||
),
|
||||
),
|
||||
)
|
||||
beego.AddNamespace(ns)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user