mirror of
https://github.com/go-admin-team/go-admin.git
synced 2026-09-22 10:33:13 +00:00
The map Authorizator receives is built by IdentityHandler in the same file and carries IdentityKey / UserName / RoleKey / UserId / RoleIds / DataScope - not user and role. Both assertions failed on every request, and because the ok result was discarded the five c.Set calls stored zero values and the function returned true anyway. Nothing in this repository or in core reads those keys. go-admin-pro has its own copy of this file and does read them; this change must not be carried over there verbatim.
197 lines
6.4 KiB
Go
197 lines
6.4 KiB
Go
package handler
|
||
|
||
import (
|
||
"go-admin/common"
|
||
"net/http"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/go-admin-team/go-admin-core/v2/captcha"
|
||
jwt "github.com/go-admin-team/go-admin-core/v2/jwtauth"
|
||
"github.com/go-admin-team/go-admin-core/v2/jwtauth/user"
|
||
"github.com/go-admin-team/go-admin-core/v2/response"
|
||
"github.com/go-admin-team/go-admin-core/v2/sdk"
|
||
"github.com/go-admin-team/go-admin-core/v2/sdk/api"
|
||
"github.com/go-admin-team/go-admin-core/v2/sdk/config"
|
||
"github.com/go-admin-team/go-admin-core/v2/sdk/pkg"
|
||
"github.com/mssola/user_agent"
|
||
"go-admin/common/global"
|
||
)
|
||
|
||
func PayloadFunc(data interface{}) jwt.MapClaims {
|
||
if v, ok := data.(map[string]interface{}); ok {
|
||
u, _ := v["user"].(SysUser)
|
||
r, _ := v["role"].(SysRole)
|
||
return jwt.MapClaims{
|
||
jwt.IdentityKey: u.UserId,
|
||
jwt.RoleIdKey: r.RoleId,
|
||
jwt.RoleKey: r.RoleKey,
|
||
jwt.NiceKey: u.Username,
|
||
jwt.DataScopeKey: r.DataScope,
|
||
jwt.RoleNameKey: r.RoleName,
|
||
// deptid completes what the data-permission scope is decided by,
|
||
// so it can be read from the token instead of joined for on every
|
||
// request. core's user.GetDeptId has always read this claim.
|
||
"deptid": u.DeptId,
|
||
}
|
||
}
|
||
return jwt.MapClaims{}
|
||
}
|
||
|
||
func IdentityHandler(c *gin.Context) interface{} {
|
||
claims := jwt.ExtractClaims(c)
|
||
return map[string]interface{}{
|
||
"IdentityKey": claims["identity"],
|
||
"UserName": claims["nice"],
|
||
"RoleKey": claims["rolekey"],
|
||
"UserId": claims["identity"],
|
||
"RoleIds": claims["roleid"],
|
||
"DataScope": claims["datascope"],
|
||
}
|
||
}
|
||
|
||
// Authenticator 获取token
|
||
// @Summary 登陆
|
||
// @Description 获取token
|
||
// @Description LoginHandler can be used by clients to get a jwt token.
|
||
// @Description Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}.
|
||
// @Description Reply will be of the form {"token": "TOKEN"}.
|
||
// @Description dev mode:It should be noted that all fields cannot be empty, and a value of 0 can be passed in addition to the account password
|
||
// @Description 注意:开发模式:需要注意全部字段不能为空,账号密码外可以传入0值
|
||
// @Tags 登陆
|
||
// @Accept application/json
|
||
// @Product application/json
|
||
// @Param account body Login true "account"
|
||
// @Success 200 {string} string "{"code": 200, "expire": "2019-08-07T12:45:48+08:00", "token": ".eyJleHAiOjE1NjUxNTMxNDgsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTU2NTE0OTU0OH0.-zvzHvbg0A" }"
|
||
// @Router /api/v1/login [post]
|
||
func Authenticator(c *gin.Context) (interface{}, error) {
|
||
log := api.GetRequestLogger(c)
|
||
db, err := pkg.GetOrm(c)
|
||
if err != nil {
|
||
log.Errorf("get db error, %s", err.Error())
|
||
response.Error(c, 500, err, "数据库连接获取失败")
|
||
return nil, jwt.ErrFailedAuthentication
|
||
}
|
||
|
||
var loginVals Login
|
||
var status = "2"
|
||
var msg = "登录成功"
|
||
var username = ""
|
||
defer func() {
|
||
LoginLogToDB(c, status, msg, username)
|
||
}()
|
||
|
||
if err = c.ShouldBind(&loginVals); err != nil {
|
||
username = loginVals.Username
|
||
msg = "数据解析失败"
|
||
status = "1"
|
||
|
||
return nil, jwt.ErrMissingLoginValues
|
||
}
|
||
if config.ApplicationConfig.Mode != "dev" {
|
||
if !captcha.Verify(loginVals.UUID, loginVals.Code, true) {
|
||
username = loginVals.Username
|
||
msg = "验证码错误"
|
||
status = "1"
|
||
|
||
return nil, jwt.ErrInvalidVerificationode
|
||
}
|
||
}
|
||
sysUser, role, e := loginVals.GetUser(db)
|
||
if e == nil {
|
||
username = loginVals.Username
|
||
|
||
return map[string]interface{}{"user": sysUser, "role": role}, nil
|
||
} else {
|
||
msg = "登录失败"
|
||
status = "1"
|
||
log.Warnf("%s login failed!", loginVals.Username)
|
||
}
|
||
return nil, jwt.ErrFailedAuthentication
|
||
}
|
||
|
||
// LoginLogToDB Write log to database
|
||
func LoginLogToDB(c *gin.Context, status string, msg string, username string) {
|
||
if !config.LoggerConfig.EnabledDB {
|
||
return
|
||
}
|
||
log := api.GetRequestLogger(c)
|
||
l := make(map[string]interface{})
|
||
|
||
ua := user_agent.New(c.Request.UserAgent())
|
||
l["ipaddr"] = common.GetClientIP(c)
|
||
l["loginLocation"] = "" // pkg.GetLocation(common.GetClientIP(c),gaConfig.ExtConfig.AMap.Key)
|
||
l["loginTime"] = pkg.GetCurrentTime()
|
||
l["status"] = status
|
||
l["remark"] = c.Request.UserAgent()
|
||
browserName, browserVersion := ua.Browser()
|
||
l["browser"] = browserName + " " + browserVersion
|
||
l["os"] = ua.OS()
|
||
l["platform"] = ua.Platform()
|
||
l["username"] = username
|
||
l["msg"] = msg
|
||
|
||
q := sdk.Runtime.GetQueuePrefix(c.Request.Host)
|
||
message, err := sdk.Runtime.GetStreamMessage("", global.LoginLog, l)
|
||
if err != nil {
|
||
log.Errorf("GetStreamMessage error, %s", err.Error())
|
||
//日志报错错误,不中断请求
|
||
} else {
|
||
err = q.Append(message)
|
||
if err != nil {
|
||
log.Errorf("Append message error, %s", err.Error())
|
||
}
|
||
}
|
||
}
|
||
|
||
// LogOut
|
||
// @Summary 退出登录
|
||
// @Description 获取token
|
||
// LoginHandler can be used by clients to get a jwt token.
|
||
// Reply will be of the form {"token": "TOKEN"}.
|
||
// @Accept application/json
|
||
// @Product application/json
|
||
// @Success 200 {string} string "{"code": 200, "msg": "成功退出系统" }"
|
||
// @Router /logout [post]
|
||
// @Security Bearer
|
||
func LogOut(c *gin.Context) {
|
||
LoginLogToDB(c, "2", "退出成功", user.GetUserName(c))
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"msg": "退出成功",
|
||
})
|
||
|
||
}
|
||
|
||
// Authorizator decides whether a parsed identity may proceed. It authorizes
|
||
// every identity IdentityHandler was able to build, which is what it has always
|
||
// done.
|
||
//
|
||
// It used to also assert data["user"] and data["role"] into app/admin/models
|
||
// types and copy five fields onto the context. Those two keys are not in the
|
||
// map: IdentityHandler builds it from the token claims and puts in
|
||
// IdentityKey / UserName / RoleKey / UserId / RoleIds / DataScope. Both
|
||
// assertions therefore failed on every request, and because the ok result was
|
||
// discarded, the five c.Set calls stored zero values and the function returned
|
||
// true regardless.
|
||
//
|
||
// Nothing in this repository or in go-admin-core reads role / roleIds /
|
||
// userId / userName / dataScope off the context - the open-source data
|
||
// permission path reads the JWT claims through
|
||
// common/actions.Permission -> user.GetUserIdStr(c). Dropping the block
|
||
// therefore removes five zero values nobody read, and with them the last
|
||
// import of app/admin from a contract package.
|
||
//
|
||
// go-admin-pro has its own copy of this file and does read those keys; this
|
||
// change must not be carried over there verbatim.
|
||
func Authorizator(data interface{}, c *gin.Context) bool {
|
||
_, ok := data.(map[string]interface{})
|
||
return ok
|
||
}
|
||
|
||
func Unauthorized(c *gin.Context, code int, message string) {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": code,
|
||
"msg": message,
|
||
})
|
||
}
|