feat: 删除不需要文件夹
This commit is contained in:
409
features/security/account.go
Normal file
409
features/security/account.go
Normal file
@@ -0,0 +1,409 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ems.agt/features/security/service"
|
||||
sysConfigService "ems.agt/features/sys_config/service"
|
||||
"ems.agt/lib/core/account"
|
||||
"ems.agt/lib/core/cache"
|
||||
"ems.agt/lib/core/conf"
|
||||
"ems.agt/lib/core/constants/cachekey"
|
||||
"ems.agt/lib/core/utils/ctx"
|
||||
"ems.agt/lib/core/vo/result"
|
||||
"ems.agt/lib/dborm"
|
||||
"ems.agt/lib/global"
|
||||
"ems.agt/lib/log"
|
||||
"ems.agt/lib/oauth"
|
||||
"ems.agt/lib/services"
|
||||
"ems.agt/restagent/config"
|
||||
"github.com/go-admin-team/go-admin-core/logger"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
var (
|
||||
UriOauthToken = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token"
|
||||
UriOauthHandshake = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake"
|
||||
|
||||
CustomUriOauthToken = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token"
|
||||
CustomUriOauthHandshake = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake"
|
||||
|
||||
// 系统登录
|
||||
UriLogin = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/login"
|
||||
CustomUriLogin = config.UriPrefix + "/securityManagement/{apiVersion}/login"
|
||||
|
||||
// 获取验证码
|
||||
UriCaptchaImage = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/captchaImage"
|
||||
CustomUriCaptchaImage = config.UriPrefix + "/securityManagement/{apiVersion}/captchaImage"
|
||||
|
||||
// 登录用户信息
|
||||
UriUserInfo = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getUserInfo"
|
||||
CustomUriUserInfo = config.UriPrefix + "/securityManagement/{apiVersion}/getUserInfo"
|
||||
|
||||
// 登录用户路由信息
|
||||
UriRouters = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getRouters"
|
||||
CustomUriRouters = config.UriPrefix + "/securityManagement/{apiVersion}/getRouters"
|
||||
)
|
||||
|
||||
func LoginFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||
log.Info("LoginFromOMC processing... ")
|
||||
|
||||
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
|
||||
if err != nil {
|
||||
log.Error("Failed to ReadAll:", err)
|
||||
services.ResponseNotFound404UriNotExist(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// check media type(content type) only support "application/json"
|
||||
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
|
||||
log.Debug("Invalid Content-Type")
|
||||
services.ResponseUnsupportedMediaType415(w)
|
||||
return
|
||||
}
|
||||
|
||||
// // check extend uri, response 404
|
||||
// if !IsValidOAuthUri(r) {
|
||||
// log.Debug("Uri is invalid")
|
||||
// services.ResponseNotFound404UriNotExist(w, r)
|
||||
// return
|
||||
// }
|
||||
|
||||
// Error process ....
|
||||
// response 400-7
|
||||
if !json.Valid([]byte(body)) {
|
||||
log.Error("Invalid Json Format")
|
||||
services.ResponseBadRequest400InvalidJson(w)
|
||||
return
|
||||
}
|
||||
|
||||
var oAuthBody oauth.OAuthBody
|
||||
_ = json.Unmarshal(body, &oAuthBody) //转为json
|
||||
//log.Debug("body:", string(body), "oAuthBody:", oAuthBody)
|
||||
|
||||
defer r.Body.Close()
|
||||
// response 400-5
|
||||
if oauth.IsWrongOAuthInfo(oAuthBody) {
|
||||
log.Error("Wrong parameter value")
|
||||
services.ResponseBadRequest400WrongParamValue(w)
|
||||
return
|
||||
}
|
||||
/*
|
||||
if oauth.IsValidOAuthInfo(oAuthBody) {
|
||||
plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType)
|
||||
log.Debug("Permission list:", plist)
|
||||
|
||||
token := globalSession.NewSession(w, r, plist)
|
||||
services.ResponseStatusOK200Login(w, token)
|
||||
} else {
|
||||
// response 400-4
|
||||
log.Debug("Authentication failed, mismatch user or password")
|
||||
|
||||
services.ResponseBadRequest400IncorrectLogin(w)
|
||||
}
|
||||
*/
|
||||
validUser, user, err := dborm.XormCheckLoginUser(oAuthBody.UserName,
|
||||
oAuthBody.Value, config.GetYamlConfig().Auth.Crypt)
|
||||
if !validUser || err != nil {
|
||||
// response 400-4
|
||||
log.Error("Authentication failed, mismatch user or password")
|
||||
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
token := oauth.GenRandToken("omc") // Generate new token to session ID
|
||||
sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
|
||||
affected, err := dborm.XormInsertSession(oAuthBody.UserName, sourceAddr, token,
|
||||
config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session)
|
||||
if err != nil {
|
||||
log.Error("Failed to XormInsertSession:", err)
|
||||
if affected == -1 {
|
||||
services.ResponseForbidden403MultiLoginNotAllowed(w)
|
||||
} else {
|
||||
services.ResponseBadRequest400IncorrectLogin(w)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
// 缓存用户信息
|
||||
account.CacheLoginUser(user)
|
||||
// 角色权限集合,管理员拥有所有权限
|
||||
userId := fmt.Sprint(user.Id)
|
||||
isAdmin := conf.IsAdmin(userId)
|
||||
roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin)
|
||||
services.ResponseStatusOK200LoginWhitRP(w, token, user, roles, perms)
|
||||
return
|
||||
}
|
||||
services.ResponseBadRequest400IncorrectLogin(w)
|
||||
}
|
||||
|
||||
func LogoutFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||
log.Info("LogoutFromOMC processing... ")
|
||||
|
||||
token, err := services.CheckFrontValidRequest(w, r)
|
||||
if err != nil {
|
||||
log.Error("Request error:", err)
|
||||
return
|
||||
}
|
||||
// // check media type(content type) only support "application/json"
|
||||
// if services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) == false {
|
||||
// log.Error("Invalid Content-Type")
|
||||
// services.ResponseUnsupportedMediaType415(w)
|
||||
// return
|
||||
// }
|
||||
|
||||
// // check extend uri, response 404
|
||||
// if !services.IsValidOAuthUri(r) {
|
||||
// log.Error("Uri is invalid")
|
||||
// services.ResponseNotFound404UriNotExist(w, r)
|
||||
// return
|
||||
// }
|
||||
|
||||
// // error processing ...
|
||||
// // 401-1 response
|
||||
// token, ret := oauth.IsCarriedToken(r)
|
||||
// if ret == false {
|
||||
// log.Error("AccessToken is not carried")
|
||||
// services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||
// return
|
||||
// }
|
||||
|
||||
se, err := dborm.XormLogoutUpdateSession(token)
|
||||
if err != nil {
|
||||
log.Error("Uri is invalid")
|
||||
services.ResponseNotFound404UriNotExist(w, r)
|
||||
return
|
||||
}
|
||||
// 清除缓存用户信息
|
||||
account.ClearLoginUser(se.AccountId)
|
||||
services.ResponseStatusOK200Null(w)
|
||||
}
|
||||
|
||||
func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||
log.Info("HandshakeFromOMC processing... ")
|
||||
|
||||
// check media type(content type) only support "application/json"
|
||||
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
|
||||
log.Debug("Invalid Content-Type")
|
||||
services.ResponseUnsupportedMediaType415(w)
|
||||
return
|
||||
}
|
||||
|
||||
// check extend uri, response 404
|
||||
if !services.IsValidOAuthUri(r) {
|
||||
log.Error("Uri is invalid")
|
||||
services.ResponseNotFound404UriNotExist(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// error processing ...
|
||||
// 401-1 response
|
||||
token, ret := oauth.IsCarriedToken(r)
|
||||
if !ret {
|
||||
log.Error("AccessToken is not carried")
|
||||
services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := dborm.XormUpdateSessionShakeTime(token)
|
||||
if err != nil {
|
||||
log.Error("Uri is invalid")
|
||||
services.ResponseNotFound404UriNotExist(w, r)
|
||||
return
|
||||
}
|
||||
services.ResponseStatusOK200Null(w)
|
||||
}
|
||||
|
||||
// 系统登录
|
||||
//
|
||||
// POST /login
|
||||
func LoginOMC(w http.ResponseWriter, r *http.Request) {
|
||||
log.Info("LoginOMC processing... ")
|
||||
var body struct {
|
||||
Username string `json:"username" binding:"required"` // Username 用户名
|
||||
Password string `json:"password" binding:"required"` // Password 用户密码
|
||||
Code string `json:"code"` // Code 验证码
|
||||
UUID string `json:"uuid"` // UUID 验证码唯一标识
|
||||
}
|
||||
err := ctx.ShouldBindJSON(r, &body)
|
||||
if err != nil {
|
||||
log.Error("Invalid Json Format")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||
return
|
||||
}
|
||||
// response 400-5
|
||||
if body.Username == "" || body.Password == "" {
|
||||
log.Error("Wrong parameter value")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||
return
|
||||
}
|
||||
|
||||
// 校验验证码
|
||||
// 从数据库配置获取验证码开关 true开启,false关闭
|
||||
captchaEnabledStr := sysConfigService.NewServiceSysConfig.SelectConfigValueByKey("sys.account.captchaEnabled")
|
||||
captchaEnabled, err := strconv.ParseBool(captchaEnabledStr)
|
||||
if err != nil {
|
||||
captchaEnabled = false
|
||||
}
|
||||
if captchaEnabled {
|
||||
if body.Code == "" || body.UUID == "" {
|
||||
log.Error("Authentication failed, mismatch captcha")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "验证码信息错误"))
|
||||
return
|
||||
}
|
||||
verifyKey := cachekey.CAPTCHA_CODE_KEY + body.UUID
|
||||
captcha, ok := cache.GetLocalTTL(verifyKey)
|
||||
if captcha == nil || !ok {
|
||||
log.Error("Authentication failed, captcha emtry")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "验证码已失效"))
|
||||
return
|
||||
}
|
||||
cache.DeleteLocalTTL(verifyKey)
|
||||
if captcha.(string) != body.Code {
|
||||
log.Error("Authentication failed, not match captcha")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "验证码错误"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
validUser, user, err := dborm.XormCheckLoginUser(body.Username, body.Password, config.GetYamlConfig().Auth.Crypt)
|
||||
if !validUser || err != nil {
|
||||
// response 400-4
|
||||
log.Error("Authentication failed, mismatch user or password")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
token := oauth.GenRandToken("omc") // Generate new token to session ID
|
||||
sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
|
||||
affected, err := dborm.XormInsertSession(body.Username, sourceAddr, token,
|
||||
config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session)
|
||||
if err != nil {
|
||||
log.Error("Failed to XormInsertSession:", err)
|
||||
if affected == -1 {
|
||||
services.ResponseForbidden403MultiLoginNotAllowed(w)
|
||||
} else {
|
||||
services.ResponseBadRequest400IncorrectLogin(w)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
// 缓存用户信息
|
||||
account.CacheLoginUser(user)
|
||||
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||
"accessToken": token,
|
||||
}))
|
||||
return
|
||||
}
|
||||
ctx.JSON(w, 200, result.Err(nil))
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
//
|
||||
// GET /captchaImage
|
||||
func CaptchaImage(w http.ResponseWriter, r *http.Request) {
|
||||
configService := sysConfigService.NewServiceSysConfig
|
||||
|
||||
// 从数据库配置获取验证码开关 true开启,false关闭
|
||||
captchaEnabledStr := configService.SelectConfigValueByKey("sys.account.captchaEnabled")
|
||||
captchaEnabled, err := strconv.ParseBool(captchaEnabledStr)
|
||||
if err != nil {
|
||||
captchaEnabled = false
|
||||
}
|
||||
if !captchaEnabled {
|
||||
ctx.JSON(w, 200, result.Ok(map[string]any{
|
||||
"captchaEnabled": captchaEnabled,
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
// 生成唯一标识
|
||||
verifyKey := ""
|
||||
data := map[string]any{
|
||||
"captchaEnabled": captchaEnabled,
|
||||
"uuid": "",
|
||||
"img": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
||||
}
|
||||
|
||||
// char 字符验证
|
||||
driverCaptcha := &base64Captcha.DriverString{
|
||||
//Height png height in pixel.
|
||||
Height: 40,
|
||||
// Width Captcha png width in pixel.
|
||||
Width: 120,
|
||||
//NoiseCount text noise count.
|
||||
NoiseCount: 4,
|
||||
//Length random string length.
|
||||
Length: 4,
|
||||
//Source is a unicode which is the rand string from.
|
||||
Source: "023456789abcdefghjkmnprstuvwxyz",
|
||||
//ShowLineOptions := OptionShowHollowLine | OptionShowSlimeLine | OptionShowSineLine .
|
||||
ShowLineOptions: base64Captcha.OptionShowHollowLine,
|
||||
//BgColor captcha image background color (optional)
|
||||
BgColor: &color.RGBA{
|
||||
R: 250,
|
||||
G: 250,
|
||||
B: 250,
|
||||
A: 255, // 不透明
|
||||
},
|
||||
}
|
||||
// 验证码生成
|
||||
id, question, answer := driverCaptcha.GenerateIdQuestionAnswer()
|
||||
// 验证码表达式解析输出
|
||||
item, err := driverCaptcha.DrawCaptcha(question)
|
||||
if err != nil {
|
||||
logger.Infof("Generate Id Question Answer %s : %v", question, err)
|
||||
} else {
|
||||
data["uuid"] = id
|
||||
data["img"] = item.EncodeB64string()
|
||||
verifyKey = cachekey.CAPTCHA_CODE_KEY + id
|
||||
cache.SetLocalTTL(verifyKey, answer, 120*time.Second)
|
||||
}
|
||||
|
||||
// 本地开发下返回验证码结果,方便接口调试
|
||||
// text, ok := cache.GetLocalTTL(verifyKey)
|
||||
// if ok {
|
||||
// data["text"] = text.(string)
|
||||
// }
|
||||
|
||||
ctx.JSON(w, 200, result.Ok(data))
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
func UserInfo(w http.ResponseWriter, r *http.Request) {
|
||||
loginUser, err := ctx.LoginUser(r)
|
||||
if err != nil {
|
||||
ctx.JSON(w, 200, result.OkData(err.Error()))
|
||||
}
|
||||
// 角色权限集合,管理员拥有所有权限
|
||||
userId := fmt.Sprint(loginUser.UserID)
|
||||
isAdmin := conf.IsAdmin(userId)
|
||||
roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin)
|
||||
|
||||
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||
"user": loginUser.User,
|
||||
"roles": roles,
|
||||
"permissions": perms,
|
||||
}))
|
||||
}
|
||||
|
||||
// 登录用户路由信息
|
||||
func Routers(w http.ResponseWriter, r *http.Request) {
|
||||
userID := ctx.LoginUserToUserID(r)
|
||||
|
||||
// 前端路由,管理员拥有所有
|
||||
isAdmin := conf.IsAdmin(userID)
|
||||
buildMenus := service.NewServiceAccount.RouteMenus(userID, isAdmin)
|
||||
ctx.JSON(w, 200, result.OkData(buildMenus))
|
||||
}
|
||||
56
features/security/service/service_account.go
Normal file
56
features/security/service/service_account.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
menuService "ems.agt/features/sys_menu/service"
|
||||
roleService "ems.agt/features/sys_role/service"
|
||||
userService "ems.agt/features/sys_user/service"
|
||||
"ems.agt/lib/core/utils/parse"
|
||||
"ems.agt/lib/core/vo"
|
||||
)
|
||||
|
||||
// 实例化服务层 ServiceAccount 结构体
|
||||
var NewServiceAccount = &ServiceAccount{
|
||||
sysUserService: userService.NewServiceSysUser,
|
||||
sysRoleService: roleService.NewServiceSysRole,
|
||||
sysMenuService: menuService.NewServiceSysMenu,
|
||||
}
|
||||
|
||||
// 账号身份操作服务 服务层处理
|
||||
type ServiceAccount struct {
|
||||
// 用户信息服务
|
||||
sysUserService *userService.ServiceSysUser
|
||||
// 角色服务
|
||||
sysRoleService *roleService.ServiceSysRole
|
||||
// 菜单服务
|
||||
sysMenuService *menuService.ServiceSysMenu
|
||||
}
|
||||
|
||||
// RoleAndMenuPerms 角色和菜单数据权限
|
||||
func (s *ServiceAccount) RoleAndMenuPerms(userId string, isAdmin bool) ([]string, []string) {
|
||||
if isAdmin {
|
||||
return []string{"admin"}, []string{"*:*:*"}
|
||||
} else {
|
||||
// 角色key
|
||||
roleGroup := []string{}
|
||||
roles := s.sysRoleService.SelectRoleListByUserId(userId)
|
||||
for _, role := range roles {
|
||||
roleGroup = append(roleGroup, role.RoleKey)
|
||||
}
|
||||
// 菜单权限key
|
||||
perms := s.sysMenuService.SelectMenuPermsByUserId(userId)
|
||||
return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms)
|
||||
}
|
||||
}
|
||||
|
||||
// RouteMenus 前端路由所需要的菜单
|
||||
func (s *ServiceAccount) RouteMenus(userId string, isAdmin bool) []vo.Router {
|
||||
var buildMenus []vo.Router
|
||||
if isAdmin {
|
||||
menus := s.sysMenuService.SelectMenuTreeByUserId("*")
|
||||
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
|
||||
} else {
|
||||
menus := s.sysMenuService.SelectMenuTreeByUserId(userId)
|
||||
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
|
||||
}
|
||||
return buildMenus
|
||||
}
|
||||
Reference in New Issue
Block a user