feat: 新增第三方登录认证和管理
This commit is contained in:
@@ -67,6 +67,52 @@ func Setup(router *gin.Engine) {
|
||||
)
|
||||
}
|
||||
|
||||
// 登录认证源
|
||||
account := controller.NewAccount
|
||||
accountGroup := router.Group("/auth")
|
||||
{
|
||||
accountGroup.GET("/login/source",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 300,
|
||||
Count: 60,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
account.LoginSource,
|
||||
)
|
||||
accountGroup.POST("/login/ldap",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 180,
|
||||
Count: 15,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
account.LDAP,
|
||||
)
|
||||
accountGroup.POST("/login/smtp",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 180,
|
||||
Count: 15,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
account.SMTP,
|
||||
)
|
||||
accountGroup.GET("/login/oauth2/authorize",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 180,
|
||||
Count: 15,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
account.OAuth2CodeURL,
|
||||
)
|
||||
accountGroup.POST("/login/oauth2/token",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 180,
|
||||
Count: 15,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
account.OAuth2Token,
|
||||
)
|
||||
}
|
||||
|
||||
// 账号注册操作处理
|
||||
{
|
||||
indexGroup.POST("/register",
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
commonConstants "be.ems/src/framework/constants/common"
|
||||
tokenConstants "be.ems/src/framework/constants/token"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
tokenUtils "be.ems/src/framework/utils/token"
|
||||
"be.ems/src/framework/vo"
|
||||
@@ -201,3 +202,11 @@ func (s *AccountController) Logout(c *gin.Context) {
|
||||
|
||||
c.JSON(200, result.OkMsg(i18n.TKey(language, "app.common.logoutSuccess")))
|
||||
}
|
||||
|
||||
// LoginSource 登录认证源
|
||||
//
|
||||
// GET /auth/login/source
|
||||
func (s AccountController) LoginSource(c *gin.Context) {
|
||||
data := s.accountService.LoginSource()
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
67
src/modules/common/controller/account_ldap.go
Normal file
67
src/modules/common/controller/account_ldap.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
commonConstants "be.ems/src/framework/constants/common"
|
||||
tokenConstants "be.ems/src/framework/constants/token"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
tokenUtils "be.ems/src/framework/utils/token"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/common/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// LDAP LDAP认证登录
|
||||
//
|
||||
// POST /auth/ldap
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Summary System Login
|
||||
// @Description System Login
|
||||
// @Router /auth/ldap [post]
|
||||
func (s AccountController) LDAP(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var body model.LoginSourceBody
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
|
||||
// 登录用户信息
|
||||
loginUser, err := s.accountService.ByLDAP(body)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
// 生成令牌,创建系统访问记录
|
||||
tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser)
|
||||
if tokenStr == "" {
|
||||
c.JSON(200, result.Err(nil))
|
||||
return
|
||||
} else {
|
||||
s.accountService.UpdateLoginDateAndIP(&loginUser)
|
||||
// 登录成功
|
||||
s.sysLogLoginService.CreateSysLogLogin(
|
||||
body.Username, commonConstants.STATUS_YES, "app.common.loginSuccess",
|
||||
ipaddr, location, os, browser,
|
||||
)
|
||||
}
|
||||
|
||||
c.JSON(200, result.OkData(map[string]any{
|
||||
tokenConstants.RESPONSE_FIELD: tokenStr,
|
||||
}))
|
||||
}
|
||||
94
src/modules/common/controller/account_oauth2.go
Normal file
94
src/modules/common/controller/account_oauth2.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
commonConstants "be.ems/src/framework/constants/common"
|
||||
tokenConstants "be.ems/src/framework/constants/token"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
tokenUtils "be.ems/src/framework/utils/token"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/common/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// OAuth2CodeURL OAuth2认证跳转登录URL
|
||||
//
|
||||
// GET /auth/login/oauth2/authorize
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Summary System Login
|
||||
// @Description System Login
|
||||
// @Router /auth/login/oauth2/authorize [get]
|
||||
func (s AccountController) OAuth2CodeURL(c *gin.Context) {
|
||||
state := c.Query("state")
|
||||
if state == "" {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: state is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
redirectURL, err := s.accountService.ByOAuth2CodeURL(state)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.Redirect(302, redirectURL)
|
||||
}
|
||||
|
||||
// OAuth2 OAuth2认证登录
|
||||
//
|
||||
// POST /auth/login/oauth2/token
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Summary System Login
|
||||
// @Description System Login
|
||||
// @Router /auth/login/oauth2/token [post]
|
||||
func (s AccountController) OAuth2Token(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var body model.LoginSourceOauth2Body
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
|
||||
// 登录用户信息
|
||||
loginUser, err := s.accountService.ByOAuth2(body)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
// 生成令牌,创建系统访问记录
|
||||
tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser)
|
||||
if tokenStr == "" {
|
||||
c.JSON(200, result.Err(nil))
|
||||
return
|
||||
} else {
|
||||
s.accountService.UpdateLoginDateAndIP(&loginUser)
|
||||
// 登录成功
|
||||
s.sysLogLoginService.CreateSysLogLogin(
|
||||
body.State, commonConstants.STATUS_YES, "app.common.loginSuccess",
|
||||
ipaddr, location, os, browser,
|
||||
)
|
||||
}
|
||||
|
||||
c.JSON(200, result.OkData(map[string]any{
|
||||
tokenConstants.RESPONSE_FIELD: tokenStr,
|
||||
}))
|
||||
}
|
||||
67
src/modules/common/controller/account_smtp.go
Normal file
67
src/modules/common/controller/account_smtp.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
commonConstants "be.ems/src/framework/constants/common"
|
||||
tokenConstants "be.ems/src/framework/constants/token"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
tokenUtils "be.ems/src/framework/utils/token"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/common/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// SMTP SMTP认证登录
|
||||
//
|
||||
// POST /auth/smtp
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Summary System Login
|
||||
// @Description System Login
|
||||
// @Router /auth/smtp [post]
|
||||
func (s AccountController) SMTP(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var body model.LoginSourceBody
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
|
||||
// 登录用户信息
|
||||
loginUser, err := s.accountService.BySMTP(body)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
// 生成令牌,创建系统访问记录
|
||||
tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser)
|
||||
if tokenStr == "" {
|
||||
c.JSON(200, result.Err(nil))
|
||||
return
|
||||
} else {
|
||||
s.accountService.UpdateLoginDateAndIP(&loginUser)
|
||||
// 登录成功
|
||||
s.sysLogLoginService.CreateSysLogLogin(
|
||||
body.Username, commonConstants.STATUS_YES, "app.common.loginSuccess",
|
||||
ipaddr, location, os, browser,
|
||||
)
|
||||
}
|
||||
|
||||
c.JSON(200, result.OkData(map[string]any{
|
||||
tokenConstants.RESPONSE_FIELD: tokenStr,
|
||||
}))
|
||||
}
|
||||
22
src/modules/common/model/login_source_vo.go
Normal file
22
src/modules/common/model/login_source_vo.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
// LoginSourceVo 认证源登录对象
|
||||
type LoginSourceVo struct {
|
||||
UID string `json:"uid"` // UID 认证源UID
|
||||
Name string `json:"name"` // Name 认证源名称
|
||||
Type string `json:"type"` // Type 认证源类型
|
||||
Icon string `json:"icon"` // Icon 认证源图标
|
||||
}
|
||||
|
||||
// LoginSourceBody 认证源用户登录对象
|
||||
type LoginSourceBody struct {
|
||||
Username string `json:"username" binding:"required"` // Username 用户名
|
||||
Password string `json:"password" binding:"required"` // Password 用户密码
|
||||
UID string `json:"uid" binding:"required"` // UID 认证源唯一标识
|
||||
}
|
||||
|
||||
// LoginSourceOauth2Body 认证源OAuth2用户登录对象
|
||||
type LoginSourceOauth2Body struct {
|
||||
Code string `json:"code" binding:"required"` // Code 授权码
|
||||
State string `json:"state" binding:"required"` // State 状态-认证源唯一标识
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
adminConstants "be.ems/src/framework/constants/admin"
|
||||
"be.ems/src/framework/constants/cachekey"
|
||||
"be.ems/src/framework/constants/common"
|
||||
@@ -12,16 +13,18 @@ import (
|
||||
"be.ems/src/framework/utils/crypto"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo"
|
||||
"be.ems/src/modules/system/model"
|
||||
"be.ems/src/modules/common/model"
|
||||
systemModel "be.ems/src/modules/system/model"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 Account 结构体
|
||||
var NewAccount = &Account{
|
||||
sysUserService: systemService.NewSysUserImpl,
|
||||
sysConfigService: systemService.NewSysConfigImpl,
|
||||
sysRoleService: systemService.NewSysRoleImpl,
|
||||
sysMenuService: systemService.NewSysMenuImpl,
|
||||
sysUserService: systemService.NewSysUserImpl,
|
||||
sysConfigService: systemService.NewSysConfigImpl,
|
||||
sysRoleService: systemService.NewSysRoleImpl,
|
||||
sysMenuService: systemService.NewSysMenuImpl,
|
||||
sysLogSourceService: systemService.NewSysLoginSource,
|
||||
}
|
||||
|
||||
// 账号身份操作服务 服务层处理
|
||||
@@ -33,7 +36,8 @@ type Account struct {
|
||||
// 角色服务
|
||||
sysRoleService systemService.ISysRole
|
||||
// 菜单服务
|
||||
sysMenuService systemService.ISysMenu
|
||||
sysMenuService systemService.ISysMenu
|
||||
sysLogSourceService *systemService.SysLoginSource // 认证源
|
||||
}
|
||||
|
||||
// ValidateCaptcha 校验验证码
|
||||
@@ -72,7 +76,7 @@ func (s *Account) LoginByUsername(username, password string) (vo.LoginUser, erro
|
||||
}
|
||||
|
||||
// 查询用户登录账号
|
||||
sysUser := s.sysUserService.SelectUserByUserName(username)
|
||||
sysUser := s.sysUserService.FindByUserName(username, "System", "#")
|
||||
if sysUser.UserName != username {
|
||||
return loginUser, fmt.Errorf("login.errNameOrPasswd")
|
||||
}
|
||||
@@ -113,7 +117,7 @@ func (s *Account) LoginByUsername(username, password string) (vo.LoginUser, erro
|
||||
// UpdateLoginDateAndIP 更新登录时间和IP
|
||||
func (s *Account) UpdateLoginDateAndIP(loginUser *vo.LoginUser) bool {
|
||||
sysUser := loginUser.User
|
||||
userInfo := model.SysUser{
|
||||
userInfo := systemModel.SysUser{
|
||||
UserID: sysUser.UserID,
|
||||
LoginIP: sysUser.LoginIP,
|
||||
LoginDate: sysUser.LoginDate,
|
||||
@@ -192,3 +196,44 @@ func (s *Account) RouteMenus(userId string, isAdmin bool) []vo.Router {
|
||||
}
|
||||
return buildMenus
|
||||
}
|
||||
|
||||
// LoginSource 登录认证源
|
||||
func (s Account) LoginSource() []model.LoginSourceVo {
|
||||
rows := s.sysLogSourceService.FindByActive("")
|
||||
data := make([]model.LoginSourceVo, 0)
|
||||
for _, v := range rows {
|
||||
data = append(data, model.LoginSourceVo{
|
||||
UID: v.UID,
|
||||
Name: v.Name,
|
||||
Type: v.Type,
|
||||
Icon: v.Icon,
|
||||
})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// initLoginSourceUser 初始化登录源用户
|
||||
func (s *Account) initLoginSourceUser(uid, sType, username, password string) systemModel.SysUser {
|
||||
sysUser := systemModel.SysUser{
|
||||
UserName: username,
|
||||
NickName: username, // 昵称使用名称账号
|
||||
Password: password, // 原始密码
|
||||
UserType: sType,
|
||||
UserSource: uid,
|
||||
Sex: "0", // 性别未选择
|
||||
Status: constants.STATUS_YES, // 账号状态激活
|
||||
DeptID: "101", // 归属部门为根节点
|
||||
CreateBy: sType, // 创建来源
|
||||
}
|
||||
|
||||
// 新增用户的角色管理
|
||||
sysUser.RoleIDs = []string{"5"}
|
||||
// 新增用户的岗位管理
|
||||
sysUser.PostIDs = []string{}
|
||||
|
||||
insertId := s.sysUserService.InsertUser(sysUser)
|
||||
if insertId != "" {
|
||||
sysUser.UserID = insertId
|
||||
}
|
||||
return s.sysUserService.FindByUserName(username, sType, uid)
|
||||
}
|
||||
|
||||
111
src/modules/common/service/account_ldap.go
Normal file
111
src/modules/common/service/account_ldap.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
adminConstants "be.ems/src/framework/constants/admin"
|
||||
"be.ems/src/framework/constants/common"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo"
|
||||
"be.ems/src/modules/common/model"
|
||||
systemModelVo "be.ems/src/modules/system/model/vo"
|
||||
)
|
||||
|
||||
// ByLDAP 登录创建用户信息
|
||||
func (s *Account) ByLDAP(body model.LoginSourceBody) (vo.LoginUser, error) {
|
||||
loginUser := vo.LoginUser{}
|
||||
rows := s.sysLogSourceService.FindByActive(body.UID)
|
||||
if len(rows) != 1 {
|
||||
return loginUser, fmt.Errorf("ldap auth source not exist")
|
||||
}
|
||||
item := rows[0]
|
||||
if item.Config == "" {
|
||||
return loginUser, fmt.Errorf("ldap auth source config is empty")
|
||||
}
|
||||
var source systemModelVo.SysLoginSourceLDAP
|
||||
if err := json.Unmarshal([]byte(item.Config), &source); err != nil {
|
||||
return loginUser, err
|
||||
}
|
||||
|
||||
// 校验LDAP用户
|
||||
err := ldapAuth(source, body.Username, body.Password)
|
||||
if err != nil {
|
||||
return loginUser, err
|
||||
}
|
||||
|
||||
// 查询用户登录账号
|
||||
sysUser := s.sysUserService.FindByUserName(body.Username, item.Type, item.UID)
|
||||
if sysUser.UserID == "" || sysUser.UserName == "" {
|
||||
sysUser = s.initLoginSourceUser(item.UID, item.Type, body.Username, body.Password)
|
||||
}
|
||||
if sysUser.UserID == "" || sysUser.UserName != body.Username {
|
||||
return loginUser, fmt.Errorf("login.errNameOrPasswd")
|
||||
}
|
||||
if sysUser.DelFlag == common.STATUS_YES {
|
||||
// 对不起,您的账号已被删除
|
||||
return loginUser, fmt.Errorf("login.errDelFlag")
|
||||
}
|
||||
if sysUser.Status == common.STATUS_NO {
|
||||
return loginUser, fmt.Errorf("login.errStatus")
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
loginUser.UserID = sysUser.UserID
|
||||
loginUser.DeptID = sysUser.DeptID
|
||||
loginUser.User = sysUser
|
||||
// 用户权限组标识
|
||||
isAdmin := config.IsAdmin(sysUser.UserID)
|
||||
if isAdmin {
|
||||
loginUser.Permissions = []string{adminConstants.PERMISSION}
|
||||
} else {
|
||||
perms := s.sysMenuService.SelectMenuPermsByUserId(sysUser.UserID)
|
||||
loginUser.Permissions = parse.RemoveDuplicates(perms)
|
||||
}
|
||||
return loginUser, nil
|
||||
}
|
||||
|
||||
// ldapAuth 校验LDAP用户
|
||||
func ldapAuth(source systemModelVo.SysLoginSourceLDAP, username, password string) error {
|
||||
// 连接LDAP
|
||||
l, err := ldap.DialURL(source.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// 绑定DN校验
|
||||
if source.BindDN != "" && source.BindPassword != "" {
|
||||
if err := l.Bind(source.BindDN, source.BindPassword); err != nil {
|
||||
return fmt.Errorf("ldap user bind %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索用户
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
source.BaseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf(source.UserFilter, ldap.EscapeFilter(username)),
|
||||
[]string{"dn", "uid"},
|
||||
nil,
|
||||
)
|
||||
sr, err := l.Search(searchRequest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ldap user search %s", err)
|
||||
}
|
||||
// for _, entry := range sr.Entries {
|
||||
// fmt.Printf("%s ==== %v\n", entry.DN, entry.GetAttributeValue("uid"))
|
||||
// }
|
||||
if len(sr.Entries) != 1 {
|
||||
return fmt.Errorf("ldap user does not exist or too many entries returned")
|
||||
}
|
||||
|
||||
// 校验密码
|
||||
if err = l.Bind(sr.Entries[0].DN, password); err != nil {
|
||||
return fmt.Errorf("ldap user bind %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
171
src/modules/common/service/account_oauth2.go
Normal file
171
src/modules/common/service/account_oauth2.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
adminConstants "be.ems/src/framework/constants/admin"
|
||||
"be.ems/src/framework/constants/common"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo"
|
||||
"be.ems/src/modules/common/model"
|
||||
systemModelVo "be.ems/src/modules/system/model/vo"
|
||||
)
|
||||
|
||||
// ByOAuth2CodeURL 获取OAuth2登录URL
|
||||
func (s *Account) ByOAuth2CodeURL(state string) (string, error) {
|
||||
rows := s.sysLogSourceService.FindByActive(state)
|
||||
if len(rows) != 1 {
|
||||
return "", fmt.Errorf("oauth2 auth source not exist")
|
||||
}
|
||||
item := rows[0]
|
||||
if item.Config == "" {
|
||||
return "", fmt.Errorf("oauth2 auth source config is empty")
|
||||
}
|
||||
var source systemModelVo.SysLoginSourceOAuth2
|
||||
json.Unmarshal([]byte(item.Config), &source)
|
||||
|
||||
conf := oauth2.Config{
|
||||
ClientID: source.ClientID,
|
||||
ClientSecret: source.ClientSecret,
|
||||
RedirectURL: source.RedirectURL,
|
||||
Scopes: source.Scopes,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: source.AuthURL,
|
||||
TokenURL: source.TokenURL,
|
||||
},
|
||||
}
|
||||
return conf.AuthCodeURL(state, oauth2.AccessTypeOffline), nil
|
||||
}
|
||||
|
||||
// ByOAuth2 登录创建用户信息
|
||||
func (s *Account) ByOAuth2(body model.LoginSourceOauth2Body) (vo.LoginUser, error) {
|
||||
loginUser := vo.LoginUser{}
|
||||
rows := s.sysLogSourceService.FindByActive(body.State)
|
||||
if len(rows) != 1 {
|
||||
return loginUser, fmt.Errorf("oauth2 auth source not exist")
|
||||
}
|
||||
item := rows[0]
|
||||
if item.Config == "" {
|
||||
return loginUser, fmt.Errorf("oauth2 auth source config is empty")
|
||||
}
|
||||
var source systemModelVo.SysLoginSourceOAuth2
|
||||
if err := json.Unmarshal([]byte(item.Config), &source); err != nil {
|
||||
return loginUser, err
|
||||
}
|
||||
|
||||
// 校验OAuth2用户
|
||||
account, err := oauth2Auth(source, body.Code)
|
||||
if err != nil {
|
||||
return loginUser, err
|
||||
}
|
||||
|
||||
// 查询用户登录账号
|
||||
sysUser := s.sysUserService.FindByUserName(account, item.Type, item.UID)
|
||||
if sysUser.UserID == "" || sysUser.UserName == "" {
|
||||
sysUser = s.initLoginSourceUser(item.UID, item.Type, account, account)
|
||||
}
|
||||
if sysUser.UserID == "" || sysUser.UserName != account {
|
||||
return loginUser, fmt.Errorf("login.errNameOrPasswd")
|
||||
}
|
||||
if sysUser.DelFlag == common.STATUS_YES {
|
||||
// 对不起,您的账号已被删除
|
||||
return loginUser, fmt.Errorf("login.errDelFlag")
|
||||
}
|
||||
if sysUser.Status == common.STATUS_NO {
|
||||
return loginUser, fmt.Errorf("login.errStatus")
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
loginUser.UserID = sysUser.UserID
|
||||
loginUser.DeptID = sysUser.DeptID
|
||||
loginUser.User = sysUser
|
||||
// 用户权限组标识
|
||||
isAdmin := config.IsAdmin(sysUser.UserID)
|
||||
if isAdmin {
|
||||
loginUser.Permissions = []string{adminConstants.PERMISSION}
|
||||
} else {
|
||||
perms := s.sysMenuService.SelectMenuPermsByUserId(sysUser.UserID)
|
||||
loginUser.Permissions = parse.RemoveDuplicates(perms)
|
||||
}
|
||||
return loginUser, nil
|
||||
}
|
||||
|
||||
// oauth2Auth 校验OAuth2用户
|
||||
func oauth2Auth(source systemModelVo.SysLoginSourceOAuth2, code string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
conf := oauth2.Config{
|
||||
ClientID: source.ClientID,
|
||||
ClientSecret: source.ClientSecret,
|
||||
RedirectURL: source.RedirectURL,
|
||||
Scopes: source.Scopes,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: source.AuthURL,
|
||||
TokenURL: source.TokenURL,
|
||||
},
|
||||
}
|
||||
token, err := conf.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 使用token创建HTTP客户端 请求用户信息
|
||||
resp, err := conf.Client(ctx, token).Get(source.UserURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// 解析用户信息
|
||||
var userInfo map[string]any
|
||||
if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 读取嵌套数据
|
||||
value, found := getValueByPath(userInfo, source.AccountField)
|
||||
if !found {
|
||||
return "", fmt.Errorf("oauth2 auth source account field not exist")
|
||||
}
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
}
|
||||
|
||||
// getValueByPath 从嵌套的 map[string]any 获取嵌套键对应的值
|
||||
func getValueByPath(data map[string]any, path string) (any, bool) {
|
||||
keys := strings.Split(path, ".") // 按照 "." 拆分路径
|
||||
return getValue(data, keys)
|
||||
}
|
||||
|
||||
// getValue 是递归查找嵌套 map 的函数
|
||||
func getValue(data map[string]any, keys []string) (any, bool) {
|
||||
if len(keys) == 0 {
|
||||
return data, false
|
||||
}
|
||||
|
||||
// 获取当前键
|
||||
key := keys[0]
|
||||
|
||||
// 获取当前键的值
|
||||
val, ok := data[key]
|
||||
if !ok {
|
||||
return nil, false // 找不到键,返回 false
|
||||
}
|
||||
|
||||
// 如果还有嵌套键,继续查找
|
||||
if len(keys) > 1 {
|
||||
// 递归查找嵌套 map
|
||||
if reflect.TypeOf(val).Kind() == reflect.Map {
|
||||
// 将 `any` 转换为 `map[string]any` 类型
|
||||
if nestedMap, ok := val.(map[string]any); ok {
|
||||
return getValue(nestedMap, keys[1:])
|
||||
}
|
||||
}
|
||||
}
|
||||
return val, true
|
||||
}
|
||||
91
src/modules/common/service/account_smtp.go
Normal file
91
src/modules/common/service/account_smtp.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/wneessen/go-mail"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
adminConstants "be.ems/src/framework/constants/admin"
|
||||
"be.ems/src/framework/constants/common"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo"
|
||||
"be.ems/src/modules/common/model"
|
||||
systemModelVo "be.ems/src/modules/system/model/vo"
|
||||
)
|
||||
|
||||
// BySMTP 登录创建用户信息
|
||||
func (s *Account) BySMTP(body model.LoginSourceBody) (vo.LoginUser, error) {
|
||||
loginUser := vo.LoginUser{}
|
||||
rows := s.sysLogSourceService.FindByActive(body.UID)
|
||||
if len(rows) != 1 {
|
||||
return loginUser, fmt.Errorf("smtp auth source not exist")
|
||||
}
|
||||
item := rows[0]
|
||||
if item.Config == "" {
|
||||
return loginUser, fmt.Errorf("smtp auth source config is empty")
|
||||
}
|
||||
var source systemModelVo.SysLoginSourceSMTP
|
||||
if err := json.Unmarshal([]byte(item.Config), &source); err != nil {
|
||||
return loginUser, err
|
||||
}
|
||||
|
||||
// 校验SMTP用户
|
||||
err := smtpAuth(source, body.Username, body.Password)
|
||||
if err != nil {
|
||||
return loginUser, err
|
||||
}
|
||||
|
||||
// 查询用户登录账号
|
||||
sysUser := s.sysUserService.FindByUserName(body.Username, item.Type, item.UID)
|
||||
if sysUser.UserID == "" || sysUser.UserName == "" {
|
||||
sysUser = s.initLoginSourceUser(item.UID, item.Type, body.Username, body.Password)
|
||||
}
|
||||
if sysUser.UserID == "" || sysUser.UserName != body.Username {
|
||||
return loginUser, fmt.Errorf("login.errNameOrPasswd")
|
||||
}
|
||||
if sysUser.DelFlag == common.STATUS_YES {
|
||||
// 对不起,您的账号已被删除
|
||||
return loginUser, fmt.Errorf("login.errDelFlag")
|
||||
}
|
||||
if sysUser.Status == common.STATUS_NO {
|
||||
return loginUser, fmt.Errorf("login.errStatus")
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
loginUser.UserID = sysUser.UserID
|
||||
loginUser.DeptID = sysUser.DeptID
|
||||
loginUser.User = sysUser
|
||||
// 用户权限组标识
|
||||
isAdmin := config.IsAdmin(sysUser.UserID)
|
||||
if isAdmin {
|
||||
loginUser.Permissions = []string{adminConstants.PERMISSION}
|
||||
} else {
|
||||
perms := s.sysMenuService.SelectMenuPermsByUserId(sysUser.UserID)
|
||||
loginUser.Permissions = parse.RemoveDuplicates(perms)
|
||||
}
|
||||
return loginUser, nil
|
||||
}
|
||||
|
||||
// smtpAuth 校验SMTP用户
|
||||
func smtpAuth(source systemModelVo.SysLoginSourceSMTP, username, password string) error {
|
||||
client, err := mail.NewClient(source.Host,
|
||||
mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover),
|
||||
mail.WithUsername(username),
|
||||
mail.WithPort(source.Port),
|
||||
mail.WithPassword(password),
|
||||
mail.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create mail client %s", err)
|
||||
}
|
||||
// 连接到邮件SMTP服务器
|
||||
if err = client.DialWithContext(context.Background()); err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
return nil
|
||||
}
|
||||
163
src/modules/system/controller/sys_login_source.go
Normal file
163
src/modules/system/controller/sys_login_source.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/modules/system/model"
|
||||
"be.ems/src/modules/system/service"
|
||||
)
|
||||
|
||||
// NewLoginSource 实例化控制层
|
||||
var NewSysLoginSource = &SysLoginSourceController{
|
||||
sysLoginSourceService: service.NewSysLoginSource,
|
||||
}
|
||||
|
||||
// SysLoginSourceController 认证源管理 控制层处理
|
||||
//
|
||||
// PATH /sys/login-source
|
||||
type SysLoginSourceController struct {
|
||||
sysLoginSourceService *service.SysLoginSource // 认证源信息服务
|
||||
}
|
||||
|
||||
// List 列表
|
||||
//
|
||||
// GET /list
|
||||
func (s SysLoginSourceController) List(c *gin.Context) {
|
||||
query := reqctx.QueryMap(c)
|
||||
rows, total := s.sysLoginSourceService.FindByPage(query)
|
||||
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
|
||||
}
|
||||
|
||||
// Info 信息
|
||||
//
|
||||
// GET /:id
|
||||
func (s SysLoginSourceController) Info(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
info := s.sysLoginSourceService.FindById(parse.Number(id))
|
||||
if info.Id == parse.Number(id) {
|
||||
c.JSON(200, resp.OkData(info))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.ErrMsg("id does not exist"))
|
||||
}
|
||||
|
||||
// Add 新增
|
||||
//
|
||||
// POST /
|
||||
func (s SysLoginSourceController) Add(c *gin.Context) {
|
||||
var body model.SysLoginSource
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.Id > 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id not is empty"))
|
||||
return
|
||||
}
|
||||
if len(body.Config) < 7 || !json.Valid([]byte(body.Config)) {
|
||||
c.JSON(200, resp.ErrMsg("config json format error"))
|
||||
return
|
||||
}
|
||||
configStr, err := s.sysLoginSourceService.CheckConfigJSON(body.Type, body.Config)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
body.Config = configStr
|
||||
|
||||
body.CreateBy = reqctx.LoginUserToUserName(c)
|
||||
insertId := s.sysLoginSourceService.Insert(body)
|
||||
if insertId > 0 {
|
||||
c.JSON(200, resp.OkData(insertId))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Err(nil))
|
||||
}
|
||||
|
||||
// Edit 更新
|
||||
//
|
||||
// PUT /
|
||||
func (s SysLoginSourceController) Edit(c *gin.Context) {
|
||||
var body model.SysLoginSource
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.Id <= 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
if len(body.Config) < 7 || !json.Valid([]byte(body.Config)) {
|
||||
c.JSON(200, resp.ErrMsg("config json format error"))
|
||||
return
|
||||
}
|
||||
configStr, err := s.sysLoginSourceService.CheckConfigJSON(body.Type, body.Config)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
body.Config = configStr
|
||||
|
||||
// 查询信息
|
||||
info := s.sysLoginSourceService.FindById(body.Id)
|
||||
if info.Id != body.Id {
|
||||
c.JSON(200, resp.ErrMsg("modification failed, data not exist"))
|
||||
return
|
||||
}
|
||||
|
||||
info.Type = body.Type
|
||||
info.Name = body.Name
|
||||
info.Icon = body.Icon
|
||||
info.Config = body.Config
|
||||
info.ActiveFlag = body.ActiveFlag
|
||||
info.Remark = body.Remark
|
||||
info.UpdateBy = reqctx.LoginUserToUserName(c)
|
||||
rowsAffected := s.sysLoginSourceService.Update(info)
|
||||
if rowsAffected > 0 {
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Err(nil))
|
||||
}
|
||||
|
||||
// Remove 删除
|
||||
//
|
||||
// DELETE /:id
|
||||
func (s SysLoginSourceController) Remove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 处理字符转id数组后去重
|
||||
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
|
||||
// 转换成int64数组类型
|
||||
ids := make([]int64, 0)
|
||||
for _, v := range uniqueIDs {
|
||||
ids = append(ids, parse.Number(v))
|
||||
}
|
||||
|
||||
rows, err := s.sysLoginSourceService.DeleteByIds(ids)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
|
||||
c.JSON(200, resp.OkMsg(msg))
|
||||
}
|
||||
@@ -181,7 +181,7 @@ func (s *SysProfileController) UpdateProfile(c *gin.Context) {
|
||||
rows := s.sysUserService.UpdateUser(sysUser)
|
||||
if rows > 0 {
|
||||
// 更新缓存用户信息
|
||||
loginUser.User = s.sysUserService.SelectUserByUserName(userName)
|
||||
loginUser.User = s.sysUserService.FindByUserName(userName, "System", "#")
|
||||
// 用户权限组标识
|
||||
isAdmin := config.IsAdmin(sysUser.UserID)
|
||||
if isAdmin {
|
||||
@@ -323,7 +323,7 @@ func (s *SysProfileController) Avatar(c *gin.Context) {
|
||||
rows := s.sysUserService.UpdateUser(sysUser)
|
||||
if rows > 0 {
|
||||
// 更新缓存用户信息
|
||||
loginUser.User = s.sysUserService.SelectUserByUserName(loginUser.User.UserName)
|
||||
loginUser.User = s.sysUserService.FindByUserName(loginUser.User.UserName, "System", "#")
|
||||
// 用户权限组标识
|
||||
isAdmin := config.IsAdmin(sysUser.UserID)
|
||||
if isAdmin {
|
||||
|
||||
@@ -526,9 +526,10 @@ func (s *SysUserController) Export(c *gin.Context) {
|
||||
"C1": i18n.TKey(language, "user.export.nick"),
|
||||
"D1": i18n.TKey(language, "user.export.role"),
|
||||
"E1": i18n.TKey(language, "user.export.deptName"),
|
||||
"F1": i18n.TKey(language, "user.export.loginIP"),
|
||||
"G1": i18n.TKey(language, "user.export.loginDate"),
|
||||
"H1": i18n.TKey(language, "user.export.status"),
|
||||
"F1": i18n.TKey(language, "user.export.userType"),
|
||||
"G1": i18n.TKey(language, "user.export.loginIP"),
|
||||
"H1": i18n.TKey(language, "user.export.loginDate"),
|
||||
"I1": i18n.TKey(language, "user.export.status"),
|
||||
// "F1": i18n.TKey(language, "user.export.sex"),
|
||||
// "E1": i18n.TKey(language, "user.export.phone"),
|
||||
// "D1": i18n.TKey(language, "user.export.email"),
|
||||
@@ -536,6 +537,8 @@ func (s *SysUserController) Export(c *gin.Context) {
|
||||
// "K1": i18n.TKey(language, "user.export.deptLeader"),
|
||||
}
|
||||
// 读取用户性别字典数据
|
||||
dictSysUserType := s.sysDictDataService.SelectDictDataByType("sys_user_type")
|
||||
// 读取用户性别字典数据
|
||||
// dictSysUserSex := s.sysDictDataService.SelectDictDataByType("sys_user_sex")
|
||||
// 从第二行开始的数据
|
||||
dataCells := make([]map[string]any, 0)
|
||||
@@ -549,6 +552,14 @@ func (s *SysUserController) Export(c *gin.Context) {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// 用户类型
|
||||
userType := row.UserType
|
||||
for _, v := range dictSysUserType {
|
||||
if row.UserType == v.DictValue && row.UserSource != "#" {
|
||||
userType = i18n.TKey(language, v.DictLabel) + " " + row.UserSource
|
||||
break
|
||||
}
|
||||
}
|
||||
// 帐号状态
|
||||
statusValue := i18n.TKey(language, "dictData.disable")
|
||||
if row.Status == "1" {
|
||||
@@ -557,7 +568,11 @@ func (s *SysUserController) Export(c *gin.Context) {
|
||||
// 用户角色, 默认导出首个
|
||||
userRole := ""
|
||||
if len(row.Roles) > 0 {
|
||||
userRole = i18n.TKey(language, row.Roles[0].RoleName)
|
||||
arr := make([]string, 0)
|
||||
for _, v := range row.Roles {
|
||||
arr = append(arr, i18n.TKey(language, v.RoleName))
|
||||
}
|
||||
userRole = strings.Join(arr, ",")
|
||||
}
|
||||
dataCells = append(dataCells, map[string]any{
|
||||
"A" + idx: row.UserID,
|
||||
@@ -565,9 +580,10 @@ func (s *SysUserController) Export(c *gin.Context) {
|
||||
"C" + idx: row.NickName,
|
||||
"D" + idx: userRole,
|
||||
"E" + idx: row.Dept.DeptName,
|
||||
"F" + idx: row.LoginIP,
|
||||
"G" + idx: date.ParseDateToStr(row.LoginDate, date.YYYY_MM_DD_HH_MM_SS),
|
||||
"H" + idx: statusValue,
|
||||
"F" + idx: userType,
|
||||
"G" + idx: row.LoginIP,
|
||||
"H" + idx: date.ParseDateToStr(row.LoginDate, date.YYYY_MM_DD_HH_MM_SS),
|
||||
"I" + idx: statusValue,
|
||||
// "E" + idx: row.PhoneNumber,
|
||||
// "F" + idx: sysUserSex,
|
||||
// "D" + idx: row.Email,
|
||||
@@ -752,7 +768,7 @@ func (s *SysUserController) ImportData(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 验证是否存在这个用户
|
||||
userInfo := s.sysUserService.SelectUserByUserName(newSysUser.UserName)
|
||||
userInfo := s.sysUserService.FindByUserName(newSysUser.UserName, "System", "#")
|
||||
if userInfo.UserName != newSysUser.UserName {
|
||||
newSysUser.CreateBy = operName
|
||||
insertId := s.sysUserService.InsertUser(newSysUser)
|
||||
|
||||
22
src/modules/system/model/sys_login_source.go
Normal file
22
src/modules/system/model/sys_login_source.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
// SysLoginSource 系统第三方认证源 sys_login_source
|
||||
type SysLoginSource struct {
|
||||
Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` // ID
|
||||
UID string `gorm:"column:uid" json:"uid"` // UID 16位长度字符串
|
||||
Type string `gorm:"column:type" json:"type" binding:"required,oneof=LDAP SMTP OAuth2"` // 认证类型 LDAP SMTP OAuth2
|
||||
Name string `gorm:"column:name" json:"name" binding:"required"` // 认证名称
|
||||
Icon string `gorm:"column:icon" json:"icon"` // 图标
|
||||
ActiveFlag string `gorm:"column:active_flag" json:"activeFlag"` // 激活标记(0未激活 1激活)
|
||||
SyncFlag string `gorm:"column:sync_flag" json:"syncFlag"` // 同步标记(0未同步 1同步)
|
||||
Config string `gorm:"column:config" json:"config" binding:"required"` // 配置JSON字符串
|
||||
CreateBy string `gorm:"column:create_by" json:"createBy"` // 创建者
|
||||
CreateTime int64 `gorm:"column:create_time" json:"createTime"` // 创建时间
|
||||
UpdateBy string `gorm:"column:update_by" json:"updateBy"` // 更新者
|
||||
UpdateTime int64 `gorm:"column:update_time" json:"updateTime"` // 更新时间
|
||||
Remark string `gorm:"column:remark" json:"remark"` // 备注
|
||||
}
|
||||
|
||||
func (*SysLoginSource) TableName() string {
|
||||
return "sys_login_source"
|
||||
}
|
||||
@@ -3,58 +3,64 @@ package model
|
||||
// SysUser 用户对象 sys_user
|
||||
type SysUser struct {
|
||||
// 用户ID
|
||||
UserID string `json:"userId"`
|
||||
UserID string `json:"userId" gorm:"column:user_id;type:bigint;primaryKey"`
|
||||
// 部门ID
|
||||
DeptID string `json:"deptId"`
|
||||
DeptID string `json:"deptId" gorm:"column:dept_id"`
|
||||
// 租户ID
|
||||
TenantID string `json:"tenantId"`
|
||||
TenantID string `json:"tenantId" gorm:"column:tenant_id"`
|
||||
// 用户账号
|
||||
UserName string `json:"userName" binding:"required"`
|
||||
UserName string `json:"userName" binding:"required" gorm:"column:user_name"`
|
||||
// 用户昵称
|
||||
NickName string `json:"nickName" binding:"required"`
|
||||
// 用户类型(sys系统用户)
|
||||
UserType string `json:"userType"`
|
||||
NickName string `json:"nickName" binding:"required" gorm:"column:nick_name"`
|
||||
// 用户类型(System系统用户)
|
||||
UserType string `json:"userType" gorm:"column:user_type"`
|
||||
UserSource string `json:"userSource" gorm:"column:user_source"` // 用户来源UID (系统#))
|
||||
// 用户邮箱
|
||||
Email string `json:"email"`
|
||||
Email string `json:"email" gorm:"column:email"`
|
||||
// 手机号码
|
||||
PhoneNumber string `json:"phonenumber"`
|
||||
PhoneNumber string `json:"phonenumber" gorm:"column:phonenumber"`
|
||||
// 用户性别(0未知 1男 2女)
|
||||
Sex string `json:"sex"`
|
||||
Sex string `json:"sex" gorm:"column:sex"`
|
||||
// 头像地址
|
||||
Avatar string `json:"avatar"`
|
||||
Avatar string `json:"avatar" gorm:"column:avatar"`
|
||||
// 密码
|
||||
Password string `json:"-"`
|
||||
Password string `json:"-" gorm:"column:password"`
|
||||
// 帐号状态(0停用 1正常)
|
||||
Status string `json:"status"`
|
||||
Status string `json:"status" gorm:"column:status"`
|
||||
// 删除标志(0代表存在 1代表删除)
|
||||
DelFlag string `json:"delFlag"`
|
||||
DelFlag string `json:"delFlag" gorm:"column:del_flag"`
|
||||
// 最后登录IP
|
||||
LoginIP string `json:"loginIp"`
|
||||
LoginIP string `json:"loginIp" gorm:"column:login_ip"`
|
||||
// 最后登录时间
|
||||
LoginDate int64 `json:"loginDate"`
|
||||
LoginDate int64 `json:"loginDate" gorm:"column:login_date"`
|
||||
// 创建者
|
||||
CreateBy string `json:"createBy"`
|
||||
CreateBy string `json:"createBy" gorm:"column:create_by"`
|
||||
// 创建时间
|
||||
CreateTime int64 `json:"createTime"`
|
||||
CreateTime int64 `json:"createTime" gorm:"column:create_time"`
|
||||
// 更新者
|
||||
UpdateBy string `json:"updateBy"`
|
||||
UpdateBy string `json:"updateBy" gorm:"column:update_by"`
|
||||
// 更新时间
|
||||
UpdateTime int64 `json:"updateTime"`
|
||||
UpdateTime int64 `json:"updateTime" gorm:"column:update_time"`
|
||||
// 备注
|
||||
Remark string `json:"remark"`
|
||||
Remark string `json:"remark" gorm:"column:remark"`
|
||||
|
||||
// ====== 非数据库字段属性 ======
|
||||
|
||||
// 部门对象
|
||||
Dept SysDept `json:"dept,omitempty" binding:"structonly"`
|
||||
Dept SysDept `json:"dept,omitempty" binding:"structonly" gorm:"-"`
|
||||
// 租户对象
|
||||
Tenant SysTenant `json:"tenant,omitempty" binding:"structonly"`
|
||||
Tenant SysTenant `json:"tenant,omitempty" binding:"structonly" gorm:"-"`
|
||||
// 角色对象组
|
||||
Roles []SysRole `json:"roles"`
|
||||
Roles []SysRole `json:"roles" gorm:"-"`
|
||||
// 角色ID
|
||||
RoleID string `json:"roleId,omitempty"`
|
||||
RoleID string `json:"roleId,omitempty" gorm:"-"`
|
||||
// 角色组
|
||||
RoleIDs []string `json:"roleIds,omitempty"`
|
||||
RoleIDs []string `json:"roleIds,omitempty" gorm:"-"`
|
||||
// 岗位组
|
||||
PostIDs []string `json:"postIds,omitempty"`
|
||||
PostIDs []string `json:"postIds,omitempty" gorm:"-"`
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*SysUser) TableName() string {
|
||||
return "sys_user"
|
||||
}
|
||||
|
||||
28
src/modules/system/model/vo/login_source.go
Normal file
28
src/modules/system/model/vo/login_source.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package vo
|
||||
|
||||
// SysLoginSourceLDAP LDAP认证源
|
||||
type SysLoginSourceLDAP struct {
|
||||
URL string `json:"url"` // LDAP 服务器(ldap://192.168.9.58:11389)
|
||||
BaseDN string `json:"baseDN"` // base DN(dc=example,dc=org)
|
||||
UserFilter string `json:"userFilter"` // 用户过滤规则((&(objectClass=organizationalPerson)(uid=%s)))
|
||||
BindDN string `json:"bindDN"` // 绑定 DN(cn=admin,dc=example,dc=org)
|
||||
BindPassword string `json:"bindPassword"` // 绑定密码(adminpassword)
|
||||
}
|
||||
|
||||
// SysLoginSourceSMTP SMTP认证源
|
||||
type SysLoginSourceSMTP struct {
|
||||
Host string `json:"host"` // SMTP 服务器(smtp.gmail.com)
|
||||
Port int `json:"port"` // SMTP 端口(587)
|
||||
}
|
||||
|
||||
// SysLoginSourceOAuth2 OAuth2认证源
|
||||
type SysLoginSourceOAuth2 struct {
|
||||
ClientID string `json:"clientID"` // 客户端ID
|
||||
ClientSecret string `json:"clientSecret"` // 客户端密钥
|
||||
AuthURL string `json:"authURL"` // 认证URL
|
||||
TokenURL string `json:"tokenURL"` // 令牌URL
|
||||
Scopes []string `json:"scopes"` // 授权范围
|
||||
RedirectURL string `json:"redirectURL"` // 重定向URL
|
||||
UserURL string `json:"userURL"` // 用户信息URL
|
||||
AccountField string `json:"accountField"` // 账号字段从用户信息中获取
|
||||
}
|
||||
@@ -39,4 +39,7 @@ type ISysDept interface {
|
||||
|
||||
// DeleteDeptById 删除部门管理信息
|
||||
DeleteDeptById(deptId string) int64
|
||||
|
||||
// SelectById 通过ID查询信息
|
||||
SelectById(deptId string) model.SysDept
|
||||
}
|
||||
|
||||
@@ -391,3 +391,25 @@ func (r *SysDeptImpl) DeleteDeptById(deptId string) int64 {
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// SelectById 通过ID查询信息
|
||||
func (r *SysDeptImpl) SelectById(deptId string) model.SysDept {
|
||||
if deptId == "" {
|
||||
return model.SysDept{}
|
||||
}
|
||||
querySql := `select d.dept_id, d.parent_id, d.ancestors,
|
||||
d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status,
|
||||
(select dept_name from sys_dept where dept_id = d.parent_id) parent_name
|
||||
from sys_dept d where d.dept_id = ?`
|
||||
results, err := datasource.RawDB("", querySql, []any{deptId})
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return model.SysDept{}
|
||||
}
|
||||
// 转换实体
|
||||
rows := r.convertResultRows(results)
|
||||
if len(rows) > 0 {
|
||||
return rows[0]
|
||||
}
|
||||
return model.SysDept{}
|
||||
}
|
||||
|
||||
150
src/modules/system/repository/sys_login_source.go
Normal file
150
src/modules/system/repository/sys_login_source.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/system/model"
|
||||
)
|
||||
|
||||
// NewSysLoginSource 实例化数据层
|
||||
var NewSysLoginSource = &SysLoginSource{}
|
||||
|
||||
// SysLoginSource 认证源数据层处理
|
||||
type SysLoginSource struct{}
|
||||
|
||||
// SelectByPage 分页查询集合
|
||||
func (r SysLoginSource) SelectByPage(query map[string]string) ([]model.SysLoginSource, int64) {
|
||||
tx := db.DB("").Model(&model.SysLoginSource{})
|
||||
// 查询条件拼接
|
||||
if v, ok := query["name"]; ok && v != "" {
|
||||
tx = tx.Where("name like ?", v+"%")
|
||||
}
|
||||
if v, ok := query["type"]; ok && v != "" {
|
||||
tx = tx.Where("type = ?", v)
|
||||
}
|
||||
if v, ok := query["beginTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = fmt.Sprintf("%s000", v)
|
||||
}
|
||||
tx = tx.Where("create_time >= ?", v)
|
||||
}
|
||||
if v, ok := query["endTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = fmt.Sprintf("%s999", v)
|
||||
}
|
||||
tx = tx.Where("create_time <= ?", v)
|
||||
}
|
||||
|
||||
// 查询结果
|
||||
var total int64 = 0
|
||||
rows := []model.SysLoginSource{}
|
||||
|
||||
// 查询数量为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// 查询数据分页
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
|
||||
err := tx.Find(&rows).Error
|
||||
if err != nil {
|
||||
return rows, total
|
||||
}
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// Select 查询集合
|
||||
func (r SysLoginSource) Select(param model.SysLoginSource) []model.SysLoginSource {
|
||||
tx := db.DB("").Model(&model.SysLoginSource{})
|
||||
// 查询条件拼接
|
||||
if param.UID != "" {
|
||||
tx = tx.Where("uid = ?", param.UID)
|
||||
}
|
||||
if param.Type != "" {
|
||||
tx = tx.Where("type = ?", param.Type)
|
||||
}
|
||||
if param.Name != "" {
|
||||
tx = tx.Where("name = ?", param.Name)
|
||||
}
|
||||
if param.ActiveFlag != "" {
|
||||
tx = tx.Where("active_flag = ?", param.ActiveFlag)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
rows := []model.SysLoginSource{}
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询信息
|
||||
func (r SysLoginSource) SelectByIds(ids []int64) []model.SysLoginSource {
|
||||
rows := []model.SysLoginSource{}
|
||||
if len(ids) <= 0 {
|
||||
return rows
|
||||
}
|
||||
tx := db.DB("").Model(&model.SysLoginSource{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id in ?", ids)
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// Insert 新增信息 返回新增数据ID
|
||||
func (r SysLoginSource) Insert(param model.SysLoginSource) int64 {
|
||||
if param.CreateBy != "" {
|
||||
ms := time.Now().UnixMilli()
|
||||
param.UpdateBy = param.CreateBy
|
||||
param.UpdateTime = ms
|
||||
param.CreateTime = ms
|
||||
}
|
||||
// 执行插入
|
||||
if err := db.DB("").Create(¶m).Error; err != nil {
|
||||
logger.Errorf("insert err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return param.Id
|
||||
}
|
||||
|
||||
// Update 修改信息 返回受影响行数
|
||||
func (r SysLoginSource) Update(param model.SysLoginSource) int64 {
|
||||
if param.Id <= 0 {
|
||||
return 0
|
||||
}
|
||||
if param.UpdateBy != "" {
|
||||
param.UpdateTime = time.Now().UnixMilli()
|
||||
}
|
||||
tx := db.DB("").Model(&model.SysLoginSource{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id = ?", param.Id)
|
||||
tx = tx.Omit("id", "create_by", "create_time")
|
||||
// 执行更新
|
||||
if err := tx.Updates(param).Error; err != nil {
|
||||
logger.Errorf("update err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息 返回受影响行数
|
||||
func (r SysLoginSource) DeleteByIds(ids []int64) int64 {
|
||||
if len(ids) <= 0 {
|
||||
return 0
|
||||
}
|
||||
tx := db.DB("").Where("id in ?", ids)
|
||||
// 执行删除
|
||||
if err := tx.Delete(&model.SysLoginSource{}).Error; err != nil {
|
||||
logger.Errorf("delete err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
@@ -27,4 +27,7 @@ type ISysRole interface {
|
||||
|
||||
// CheckUniqueRole 校验角色是否唯一
|
||||
CheckUniqueRole(sysRole model.SysRole) string
|
||||
|
||||
// SelectByUserId 根据用户ID获取角色信息
|
||||
SelectByUserId(userId string) []model.SysRole
|
||||
}
|
||||
|
||||
@@ -373,3 +373,14 @@ func (r *SysRoleImpl) CheckUniqueRole(sysRole model.SysRole) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// SelectByUserId 根据用户ID获取角色信息
|
||||
func (r *SysRoleImpl) SelectByUserId(userId string) []model.SysRole {
|
||||
querySql := r.selectSql + " where r.del_flag = '0' and ur.user_id = ?"
|
||||
results, err := datasource.RawDB("", querySql, []any{userId})
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return []model.SysRole{}
|
||||
}
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
@@ -30,4 +30,7 @@ type ISysUser interface {
|
||||
|
||||
// CheckUniqueUser 校验用户信息是否唯一
|
||||
CheckUniqueUser(sysUser model.SysUser) string
|
||||
|
||||
// SelectByUserName 通过登录账号查询信息
|
||||
SelectByUserName(userName, userType, userSource string) model.SysUser
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
// 实例化数据层 SysUserImpl 结构体
|
||||
var NewSysUserImpl = &SysUserImpl{
|
||||
selectSql: `select
|
||||
u.user_id, u.dept_id, u.tenant_id, u.user_name, u.nick_name, u.user_type, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
|
||||
u.user_id, u.dept_id, u.tenant_id, u.user_name, u.nick_name, u.user_type, u.user_source, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
|
||||
d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
|
||||
t.tenant_id, t.parent_id, t.ancestors, t.tenant_name, t.order_num, t.tenancy_type, t.tenancy_key, t.status as tenant_status,
|
||||
r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
|
||||
@@ -33,6 +33,7 @@ var NewSysUserImpl = &SysUserImpl{
|
||||
"user_name": "UserName",
|
||||
"nick_name": "NickName",
|
||||
"user_type": "UserType",
|
||||
"user_source": "UserSource",
|
||||
"email": "Email",
|
||||
"phonenumber": "PhoneNumber",
|
||||
"sex": "Sex",
|
||||
@@ -171,6 +172,14 @@ func (r *SysUserImpl) SelectUserPage(query map[string]any, dataScopeSQL string)
|
||||
conditions = append(conditions, "u.phonenumber like concat(?, '%')")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["userType"]; ok && v != "" {
|
||||
conditions = append(conditions, "u.user_type = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["userSource"]; ok && v != "" {
|
||||
conditions = append(conditions, "u.user_source = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
beginTime, ok := query["beginTime"]
|
||||
if !ok {
|
||||
beginTime, ok = query["params[beginTime]"]
|
||||
@@ -398,6 +407,32 @@ func (r *SysUserImpl) SelectUserByIds(userIds []string) []model.SysUser {
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectByUserName 通过登录账号查询信息
|
||||
func (r *SysUserImpl) SelectByUserName(userName, userType, userSource string) model.SysUser {
|
||||
item := model.SysUser{}
|
||||
if userName == "" {
|
||||
return item
|
||||
}
|
||||
if userType == "" {
|
||||
userType = "System"
|
||||
}
|
||||
if userSource == "" {
|
||||
userSource = "#"
|
||||
}
|
||||
querySql := r.selectSql + " where u.del_flag = '0' and u.user_name = ? and u.user_type = ? and u.user_source = ?"
|
||||
results, err := datasource.RawDB("", querySql, []any{userName, userType, userSource})
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return model.SysUser{}
|
||||
}
|
||||
// 转换实体
|
||||
rows := r.convertResultRows(results)
|
||||
if len(rows) > 0 {
|
||||
return rows[0]
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
// SelectUserByUserName 通过用户登录账号查询用户
|
||||
func (r *SysUserImpl) SelectUserByUserName(userName string) model.SysUser {
|
||||
querySql := r.selectSql + " where u.del_flag = '0' and u.user_name = ?"
|
||||
@@ -436,6 +471,9 @@ func (r *SysUserImpl) InsertUser(sysUser model.SysUser) string {
|
||||
if sysUser.UserType != "" {
|
||||
params["user_type"] = sysUser.UserType
|
||||
}
|
||||
if sysUser.UserSource != "" {
|
||||
params["user_source"] = sysUser.UserSource
|
||||
}
|
||||
if sysUser.Avatar != "" {
|
||||
params["avatar"] = sysUser.Avatar
|
||||
}
|
||||
@@ -509,6 +547,9 @@ func (r *SysUserImpl) UpdateUser(sysUser model.SysUser) int64 {
|
||||
if sysUser.UserType != "" {
|
||||
params["user_type"] = sysUser.UserType
|
||||
}
|
||||
if sysUser.UserSource != "" {
|
||||
params["user_source"] = sysUser.UserSource
|
||||
}
|
||||
if sysUser.Avatar != "" {
|
||||
params["avatar"] = sysUser.Avatar
|
||||
}
|
||||
@@ -582,6 +623,14 @@ func (r *SysUserImpl) CheckUniqueUser(sysUser model.SysUser) string {
|
||||
conditions = append(conditions, "email = ?")
|
||||
params = append(params, sysUser.Email)
|
||||
}
|
||||
if sysUser.UserType != "" {
|
||||
conditions = append(conditions, "user_type = ?")
|
||||
params = append(params, sysUser.UserType)
|
||||
}
|
||||
if sysUser.UserSource != "" {
|
||||
conditions = append(conditions, "user_source = ?")
|
||||
params = append(params, sysUser.UserSource)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
|
||||
95
src/modules/system/service/sys_login_source.go
Normal file
95
src/modules/system/service/sys_login_source.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"be.ems/src/framework/utils/generate"
|
||||
"be.ems/src/modules/system/model"
|
||||
"be.ems/src/modules/system/model/vo"
|
||||
"be.ems/src/modules/system/repository"
|
||||
)
|
||||
|
||||
// NewSysLoginSource 实例化服务层
|
||||
var NewSysLoginSource = &SysLoginSource{
|
||||
sysLoginSourceRepository: repository.NewSysLoginSource,
|
||||
}
|
||||
|
||||
// SysLoginSource 认证源 服务层处理
|
||||
type SysLoginSource struct {
|
||||
sysLoginSourceRepository *repository.SysLoginSource // 认证源表
|
||||
}
|
||||
|
||||
// FindByPage 分页查询
|
||||
func (s SysLoginSource) FindByPage(query map[string]string) ([]model.SysLoginSource, int64) {
|
||||
return s.sysLoginSourceRepository.SelectByPage(query)
|
||||
}
|
||||
|
||||
// FindById 查询ID
|
||||
func (s SysLoginSource) FindById(id int64) model.SysLoginSource {
|
||||
rows := s.sysLoginSourceRepository.SelectByIds([]int64{id})
|
||||
if len(rows) > 0 {
|
||||
return rows[0]
|
||||
}
|
||||
return model.SysLoginSource{}
|
||||
}
|
||||
|
||||
// Insert 新增
|
||||
func (s SysLoginSource) Insert(param model.SysLoginSource) int64 {
|
||||
param.UID = generate.Code(8)
|
||||
return s.sysLoginSourceRepository.Insert(param)
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (s SysLoginSource) Update(param model.SysLoginSource) int64 {
|
||||
return s.sysLoginSourceRepository.Update(param)
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除
|
||||
func (s SysLoginSource) DeleteByIds(ids []int64) (int64, error) {
|
||||
// 检查是否存在
|
||||
arr := s.sysLoginSourceRepository.SelectByIds(ids)
|
||||
if len(arr) <= 0 {
|
||||
// return 0, fmt.Errorf("没有权限访问认证源数据!")
|
||||
return 0, fmt.Errorf("no permission to access authentication source data")
|
||||
}
|
||||
if len(arr) == len(ids) {
|
||||
return s.sysLoginSourceRepository.DeleteByIds(ids), nil
|
||||
}
|
||||
// return 0, fmt.Errorf("删除认证源信息失败!")
|
||||
return 0, fmt.Errorf("failed to delete authentication source information")
|
||||
}
|
||||
|
||||
// FindByActive 查询激活
|
||||
func (s SysLoginSource) FindByActive(uid string) []model.SysLoginSource {
|
||||
param := model.SysLoginSource{
|
||||
ActiveFlag: "1",
|
||||
}
|
||||
if uid != "" {
|
||||
param.UID = uid
|
||||
}
|
||||
return s.sysLoginSourceRepository.Select(param)
|
||||
}
|
||||
|
||||
// CheckConfigJSON 检查配置JSON
|
||||
func (s SysLoginSource) CheckConfigJSON(sType, sConfig string) (string, error) {
|
||||
var source any
|
||||
switch sType {
|
||||
case "LDAP":
|
||||
source = new(vo.SysLoginSourceLDAP)
|
||||
case "SMTP":
|
||||
source = new(vo.SysLoginSourceSMTP)
|
||||
case "OAuth2":
|
||||
source = new(vo.SysLoginSourceOAuth2)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported login source type: %s", sType)
|
||||
}
|
||||
if err := json.Unmarshal([]byte(sConfig), &source); err != nil {
|
||||
return "", fmt.Errorf("config json format error for %s type: %s", sType, err.Error())
|
||||
}
|
||||
configByte, err := json.Marshal(source)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("config json format error")
|
||||
}
|
||||
return string(configByte), nil
|
||||
}
|
||||
@@ -13,6 +13,11 @@ type ISysUser interface {
|
||||
// SelectAllocatedPage 根据条件分页查询分配用户角色列表
|
||||
SelectAllocatedPage(query map[string]any, dataScopeSQL string) map[string]any
|
||||
|
||||
// FindByUserName 通过用户名查询用户信息
|
||||
// userType 系统sys
|
||||
// userSource 系统#
|
||||
FindByUserName(userName, userType, userSource string) model.SysUser
|
||||
|
||||
// SelectUserByUserName 通过用户名查询用户
|
||||
SelectUserByUserName(userName string) model.SysUser
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ var NewSysUserImpl = &SysUserImpl{
|
||||
sysUserRepository: repository.NewSysUserImpl,
|
||||
sysUserRoleRepository: repository.NewSysUserRoleImpl,
|
||||
sysUserPostRepository: repository.NewSysUserPostImpl,
|
||||
sysDeptRepository: repository.NewSysDeptImpl,
|
||||
sysRoleRepository: repository.NewSysRoleImpl,
|
||||
}
|
||||
|
||||
// SysUserImpl 用户 服务层处理
|
||||
@@ -23,6 +25,10 @@ type SysUserImpl struct {
|
||||
sysUserRoleRepository repository.ISysUserRole
|
||||
// 用户与岗位服务
|
||||
sysUserPostRepository repository.ISysUserPost
|
||||
// 部门服务
|
||||
sysDeptRepository repository.ISysDept
|
||||
// 角色服务
|
||||
sysRoleRepository repository.ISysRole
|
||||
}
|
||||
|
||||
// SelectUserPage 根据条件分页查询用户列表
|
||||
@@ -40,6 +46,30 @@ func (r *SysUserImpl) SelectAllocatedPage(query map[string]any, dataScopeSQL str
|
||||
return r.sysUserRepository.SelectAllocatedPage(query, dataScopeSQL)
|
||||
}
|
||||
|
||||
// FindByUserName 通过用户名查询用户信息
|
||||
// userType 系统sys
|
||||
// userSource 系统#
|
||||
func (s SysUserImpl) FindByUserName(userName, userType, userSource string) model.SysUser {
|
||||
userinfo := s.sysUserRepository.SelectByUserName(userName, userType, userSource)
|
||||
if userinfo.UserName != userName {
|
||||
return userinfo
|
||||
}
|
||||
// 部门
|
||||
deptInfo := s.sysDeptRepository.SelectById(userinfo.DeptID)
|
||||
userinfo.Dept = deptInfo
|
||||
// 角色
|
||||
roleArr := s.sysRoleRepository.SelectByUserId(userinfo.UserID)
|
||||
roles := make([]model.SysRole, 0)
|
||||
roleIds := make([]string, 0)
|
||||
for _, role := range roleArr {
|
||||
roles = append(roles, role)
|
||||
roleIds = append(roleIds, role.RoleID)
|
||||
}
|
||||
userinfo.Roles = roles
|
||||
userinfo.RoleIDs = roleIds
|
||||
return userinfo
|
||||
}
|
||||
|
||||
// SelectUserByUserName 通过用户名查询用户
|
||||
func (r *SysUserImpl) SelectUserByUserName(userName string) model.SysUser {
|
||||
return r.sysUserRepository.SelectUserByUserName(userName)
|
||||
@@ -147,7 +177,9 @@ func (r *SysUserImpl) DeleteUserByIds(userIds []string) (int64, error) {
|
||||
// CheckUniqueUserName 校验用户名称是否唯一
|
||||
func (r *SysUserImpl) CheckUniqueUserName(userName, userId string) bool {
|
||||
uniqueId := r.sysUserRepository.CheckUniqueUser(model.SysUser{
|
||||
UserName: userName,
|
||||
UserName: userName,
|
||||
UserType: "System",
|
||||
UserSource: "#",
|
||||
})
|
||||
if uniqueId == userId {
|
||||
return true
|
||||
@@ -159,6 +191,8 @@ func (r *SysUserImpl) CheckUniqueUserName(userName, userId string) bool {
|
||||
func (r *SysUserImpl) CheckUniquePhone(phonenumber, userId string) bool {
|
||||
uniqueId := r.sysUserRepository.CheckUniqueUser(model.SysUser{
|
||||
PhoneNumber: phonenumber,
|
||||
UserType: "System",
|
||||
UserSource: "#",
|
||||
})
|
||||
if uniqueId == userId {
|
||||
return true
|
||||
@@ -169,7 +203,9 @@ func (r *SysUserImpl) CheckUniquePhone(phonenumber, userId string) bool {
|
||||
// CheckUniqueEmail 校验email是否唯一
|
||||
func (r *SysUserImpl) CheckUniqueEmail(email, userId string) bool {
|
||||
uniqueId := r.sysUserRepository.CheckUniqueUser(model.SysUser{
|
||||
Email: email,
|
||||
Email: email,
|
||||
UserType: "System",
|
||||
UserSource: "#",
|
||||
})
|
||||
if uniqueId == userId {
|
||||
return true
|
||||
|
||||
@@ -472,6 +472,35 @@ func Setup(router *gin.Engine) {
|
||||
controller.NewSysLogLogin.Export,
|
||||
)
|
||||
}
|
||||
|
||||
// 第三方认证-配置认证源
|
||||
sysLoginSource := controller.NewSysLoginSource
|
||||
sysLoginSourceGroup := router.Group("/system/login-source")
|
||||
{
|
||||
sysLoginSourceGroup.GET("/list",
|
||||
middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:list"}}),
|
||||
sysLoginSource.List,
|
||||
)
|
||||
sysLoginSourceGroup.GET("/:id",
|
||||
middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:query"}}),
|
||||
sysLoginSource.Info,
|
||||
)
|
||||
sysLoginSourceGroup.POST("",
|
||||
middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:add"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysLoginSource", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
sysLoginSource.Add,
|
||||
)
|
||||
sysLoginSourceGroup.PUT("",
|
||||
middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:edit"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysLoginSource", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
sysLoginSource.Edit,
|
||||
)
|
||||
sysLoginSourceGroup.DELETE("/:id",
|
||||
middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:remove"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysLoginSource", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
sysLoginSource.Remove,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// InitLoad 初始参数
|
||||
|
||||
Reference in New Issue
Block a user