JM-WechatMini/oauth2/handle/oauth2.go
2024-03-21 21:08:45 +08:00

185 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handle
import (
"context"
"encoding/json"
er "errors"
"fmt"
"git.echol.cn/loser/logger/log"
"github.com/go-oauth2/oauth2/v4"
"github.com/go-oauth2/oauth2/v4/errors"
"miniapp/client"
"miniapp/model/app"
"miniapp/model/cache"
"miniapp/model/common/constant"
"miniapp/service"
"net/http"
"strconv"
"strings"
"time"
)
// UserAuthorizationHandler 获取用户Id
func UserAuthorizationHandler(w http.ResponseWriter, r *http.Request) (userId string, err error) {
loginType := constant.LoginType(r.FormValue("type")) // 登录类型
userIdentity := constant.UserIdentity(r.FormValue("identity")) // 身份类型
account := r.FormValue("username") // 用户传入账号(或者授权Code)
nikeName := r.FormValue("nickName") // 昵称
avatarUrl := r.FormValue("avatarUrl") // 头像
log.Debugf("预处理用户登录请求,身份类型: %v => 登录类型: %s => 账号: %v", userIdentity, loginType, account)
var roleCode []string
// 处理用户Id
switch userIdentity {
case constant.UserIdentityAdmin:
// 管理员
case constant.UserIdentityUser:
// 普通用户
userId, err = getUser(account, loginType, nikeName, avatarUrl)
default:
err = er.New("未知的用户身份类型")
}
if err != nil {
return
}
// 组装缓存用户信息
m := cache.UserInfo{
RoleCodes: strings.Join(roleCode, ","),
UserId: userId,
UserType: userIdentity.String(),
}
userInfo, err := m.String()
if err != nil {
err = errors.New("登录失败,请联系管理员")
return
}
if err = client.Redis.Set(context.Background(), fmt.Sprintf("%s%v", constant.OAuth2UserCacheKey, userId), userInfo, time.Hour*24*7).Err(); err != nil {
log.Errorf("缓存用户信息失败用户ID%v错误信息%s", userId, err.Error())
err = errors.New("登录失败,请联系管理员")
return
}
return
}
// LoginWithPassword 账号密码登录模式
func LoginWithPassword(ctx context.Context, clientId, userId, password string) (userID string, err error) {
log.Debugf("[%v]处理登录请求用户Id%s --> %s", clientId, userId, password)
userID = userId
return
}
// CheckClient 检查是否允许该客户端通过该授权模式请求令牌
func CheckClient(clientID string, grant oauth2.GrantType) (allowed bool, err error) {
// 解出租户Id和传入的客户端Id
c := app.OAuth2Client{ClientId: clientID}
// 查询客户端配置信息
if err = service.ServiceGroupApp.AppServiceGroup.Oauth2ClientService.FindOne(&c); err != nil {
log.Errorf("客户端信息查询失败: %v", err.Error())
err = errors.New("客户端信息查询失败: " + err.Error())
allowed = false
return
}
// 判断是否包含授权范围
allowed = strings.Contains(c.Grant, string(grant))
if !allowed {
err = errors.New("不受允许的grant_type")
}
return
}
// ExtensionFields 自定义响应Token的扩展字段
func ExtensionFields(ti oauth2.TokenInfo) (fieldsValue map[string]any) {
fieldsValue = map[string]any{}
fieldsValue["license"] = "Made By Lee"
// 取出用户信息
var userInfo app.User
tid, _ := strconv.Atoi(ti.GetUserID())
userInfo.ID = uint(tid)
//if err := repository.User().GetUser(&userInfo); err != nil {
// return
//}
service.ServiceGroupApp.AppServiceGroup.UserService.GetUser(&userInfo)
fieldsValue["newUser"] = time.Now().Sub(userInfo.CreatedAt).Minutes() <= 1
fieldsValue["nickname"] = userInfo.Nickname
fieldsValue["phone"] = userInfo.Phone
fieldsValue["userId"] = userInfo.ID
fieldsValue["avatar"] = userInfo.Avatar
fieldsValue["TimeNote"] = userInfo.Avatar
fieldsValue["IsSurgery"] = userInfo.IsSurgery
fieldsValue["HospitalId"] = userInfo.HospitalId
fieldsValue["IsInfo"] = userInfo.IsInfo
fieldsValue["SurgeryTime"] = userInfo.SurgeryTime
fieldsValue["HospitalId"] = userInfo.HospitalId
fieldsValue["IsSurgery"] = userInfo.IsSurgery
return
}
// ResponseToken 返回Token生成结果
func ResponseToken(w http.ResponseWriter, data map[string]any, header http.Header, statusCode ...int) error {
log.Debugf("返回Token原始数据: %+v", data)
type response struct {
Code int `json:"code"`
Data map[string]any `json:"data"`
Msg string `json:"message"`
}
status := http.StatusOK
msg := "login success"
if len(statusCode) > 0 && statusCode[0] > 0 {
status = statusCode[0]
msg = fmt.Sprintf("%v", data["error_description"])
// 处理特殊返回 - 刷新Token到期了
switch data["error"] {
case "invalid_grant":
msg = "登录已过期,请重新授权登录"
case "invalid_request":
msg = "登录参数错误"
default:
log.Errorf("收到未定义的登录错误: %v", data["error_description"])
}
data = nil
}
res := response{
Code: status,
Msg: msg,
Data: data,
}
jsonBytes, err := json.Marshal(res)
if err != nil {
return err
}
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("Pragma", "no-cache")
for key := range header {
w.Header().Set(key, header.Get(key))
}
w.WriteHeader(status)
_, err = w.Write(jsonBytes)
if err != nil {
log.Errorf("返回Token失败: %v", err.Error())
return err
}
return err
}
// InternalErrorHandler 自定义内部错误处理
func InternalErrorHandler(err error) (re *errors.Response) {
re = errors.NewResponse(err, http.StatusUnauthorized)
re.Description = err.Error()
return
}