作者 yangfu

feat: 2.0 访问权限验证、角色修改

正在显示 28 个修改的文件 包含 416 行增加251 行删除
... ... @@ -5,7 +5,6 @@ import (
"github.com/samber/lo"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/open"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/tool"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
... ... @@ -34,8 +33,8 @@ func (l *ChatSessionGetLogic) ChatSessionGet(req *types.ChatSessionGetRequest) (
conn = l.svcCtx.DefaultDBConn()
session *domain.ChatSession
records []*domain.ChatSessionRecord
token = contextdata.GetUserTokenFromCtx(l.ctx)
user open.User
//token = contextdata.GetUserTokenFromCtx(l.ctx)
user open.User
)
// 货号唯一
if session, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.Id); err != nil {
... ... @@ -44,14 +43,14 @@ func (l *ChatSessionGetLogic) ChatSessionGet(req *types.ChatSessionGetRequest) (
if user, err = l.svcCtx.SystemOpen.User(l.ctx, conn, session.UserId); err != nil {
return nil, xerr.NewErrMsgErr("用户不存在", err)
}
if _, records, err = l.svcCtx.ChatSessionRecordRepository.FindByCompanyUser(l.ctx, conn, token.CompanyId, token.UserId, domain.NewQueryOptions().MustWithKV("sessionId", session.Id)); err != nil {
if _, records, err = l.svcCtx.ChatSessionRecordRepository.FindByCompanyUser(l.ctx, conn, session.CompanyId, session.UserId, domain.NewQueryOptions().MustWithKV("sessionId", session.Id)); err != nil {
return nil, xerr.NewErr(err)
}
var typesRecords []types.Record
lo.ForEach(records, func(item *domain.ChatSessionRecord, index int) {
typesRecords = append(typesRecords, NewTypesChatRecord(item, user))
})
var documents []types.ChatDocumentItem
var documents = make([]types.ChatDocumentItem, 0)
var dataset types.ChatDatasetItem
if session.Type == domain.TypeSparkDocumentsChat && len(session.Metadata.DocumentIds) > 0 {
for _, id := range session.Metadata.DocumentIds {
... ...
... ... @@ -9,7 +9,9 @@ import (
type Config struct {
rest.RestConf
config.Config
Redis redis.RedisConf `json:",optional"`
SystemAuth config.Auth
DebugSmsCode string `json:",optional,default=999512"`
Redis redis.RedisConf `json:",optional"`
SystemAuth config.Auth
DebugSmsCode string `json:",optional,default=999512"`
CheckAuth bool `json:",optional,default=true"`
CheckAuthProba float64 `json:",optional,default=0.3"`
}
... ...
package app
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/app"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemAppListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.SystemAppSearchRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := app.NewSystemAppListLogic(r.Context(), svcCtx)
resp, err := l.SystemAppList(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
... ... @@ -38,7 +38,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.LogRequest},
[]rest.Middleware{serverCtx.LogRequest, serverCtx.LoginStatusCheck},
[]rest.Route{
{
Method: http.MethodPost,
... ... @@ -220,6 +220,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/system/app/set_config",
Handler: app.SystemAppSetConfigHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/system/app/list",
Handler: app.SystemAppListHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.SystemAuth.AccessSecret),
... ...
package app
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type SystemAppListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewSystemAppListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SystemAppListLogic {
return &SystemAppListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *SystemAppListLogic) SystemAppList(req *types.SystemAppSearchRequest) (resp interface{}, err error) {
logic := NewSystemAppSearchLogic(l.ctx, l.svcCtx)
var tmpResp *types.SystemAppSearchResponse
tmpResp, err = logic.SystemAppSearch(req)
list := make([]types.App, 0)
for _, item := range tmpResp.List {
list = append(list, types.App{
Id: item.Id,
Name: item.Name,
Logo: item.Logo,
})
}
resp = map[string]interface{}{
"list": list,
}
return
}
... ...
... ... @@ -106,5 +106,6 @@ func NewTypesSystemAppItem(item *domain.SysApp, cp *domain.SysCompanyApp) types.
VisibleFlag: cp.VisibleFlag,
VisibleUsers: cp.VisibleUsers,
Sort: cp.Sort,
Url: item.Url,
}
}
... ...
... ... @@ -85,6 +85,10 @@ func (l *SystemAuthLoginLogic) SystemAuthLogin(req *types.AuthLoginRequest) (res
EmployeeId: currentEmployee.Id,
}
token, _ := userToken.GenerateToken(l.svcCtx.Config.SystemAuth.AccessSecret, l.svcCtx.Config.SystemAuth.AccessExpire)
// 保存Token
if err = l.svcCtx.UserAuthService.Refresh(user.Id, token); err != nil {
return nil, xerr.NewErr(err)
}
resp = &types.AuthLoginResponse{
Token: token,
}
... ...
... ... @@ -55,6 +55,12 @@ func (l *SystemAuthSwitchCompanyLogic) SystemAuthSwitchCompany(req *types.Switch
EmployeeId: employee.Id,
}
tokenStr, _ := userToken.GenerateToken(l.svcCtx.Config.SystemAuth.AccessSecret, l.svcCtx.Config.SystemAuth.AccessExpire)
// 保存Token
if err = l.svcCtx.UserAuthService.Refresh(user.Id, tokenStr); err != nil {
return nil, xerr.NewErr(err)
}
resp = &types.AuthLoginResponse{
Token: tokenStr,
}
... ...
... ... @@ -75,7 +75,7 @@ func (l *SystemAuthUserInfoLogic) GetUserAuthMenus(userId int64, companyId int64
if !lo.Contains(role.AuthUsers, userId) {
continue
}
if role.AuthRange == domain.AuthRangeAll {
if role.AuthRange == domain.AuthRangeAllMenu {
hasAllAuth = true
}
menusSet.Add(lo.ToAnySlice(role.Menus)...)
... ... @@ -111,6 +111,15 @@ func (l *SystemAuthUserInfoLogic) GetUserApps(userId int64, companyId int64) []t
err error
)
var appSets = collection.NewSet()
_, roles, _ := l.svcCtx.RoleRepository.FindByEmployee(l.ctx, conn, companyId, userId, domain.NewQueryOptions().WithFindOnly())
for _, role := range roles {
if !lo.Contains(role.Apps, userId) {
continue
}
appSets.Add(lo.ToAnySlice(role.Apps)...)
}
if _, companyApps, err = l.svcCtx.CompanyAppRepository.Find(l.ctx, conn, domain.NewQueryOptions().WithFindOnly().MustWithKV("companyId", companyId)); err != nil {
return typesApps
}
... ... @@ -120,12 +129,19 @@ func (l *SystemAuthUserInfoLogic) GetUserApps(userId int64, companyId int64) []t
if app == nil {
continue
}
// 角色包含应用权限
typeApp := types.NewTypesSystemAppItem(app, companyApp)
// 有指定用户权限
if len(companyApp.VisibleUsers) > 0 && lo.Contains(companyApp.VisibleUsers, userId) {
if appSets.Contains(app.Id) {
typeApp.HasAuth = true
}
// 有部门权限
// 指定用户包含应用权限
if !(typeApp.HasAuth) && len(companyApp.VisibleUsers) > 0 && lo.Contains(companyApp.VisibleUsers, userId) {
typeApp.HasAuth = true
}
// 部门包含应用权限
if !(typeApp.HasAuth) && len(companyApp.VisibleDepartments) > 0 {
_, departments, _ := l.svcCtx.UserDepartmentRepository.FindByUser(l.ctx, conn, companyId, []int64{userId})
if lo.ContainsBy(departments, func(item *domain.SysUserDepartment) bool {
... ... @@ -139,6 +155,11 @@ func (l *SystemAuthUserInfoLogic) GetUserApps(userId int64, companyId int64) []t
typeApp.HasAuth = true
}
}
//if !typeApp.HasAuth {
// continue
//}
typesApps = append(typesApps, typeApp)
}
return typesApps
... ...
... ... @@ -2,6 +2,7 @@ package role
import (
"context"
"github.com/samber/lo"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
... ... @@ -36,17 +37,48 @@ func (l *SystemRoleGetLogic) SystemRoleGet(req *types.RoleGetRequest) (resp *typ
}
userLazyLoad := domain.NewLazyLoadService(l.svcCtx.UserRepository.FindOne)
menuLazyLoad := domain.NewLazyLoadService(domain.FineOneMenu)
appLazyLoad := domain.NewLazyLoadService(l.svcCtx.AppRepository.FindOne)
departmentLazyLoad := domain.NewLazyLoadService(l.svcCtx.DepartmentRepository.FindOne)
role := NewTypesSysRole(dm)
for _, userId := range dm.AuthUsers {
if user, _ := userLazyLoad.Load(l.ctx, conn, userId); user != nil {
role.AuthUsers = append(role.AuthUsers, types.NewTypesUser(user))
}
}
// 查询用户部门
if len(dm.AuthUsers) > 0 {
_, userDeps, _ := l.svcCtx.UserDepartmentRepository.FindByUser(l.ctx, conn, dm.CompanyId, dm.AuthUsers)
userDepsGroup := lo.GroupBy(userDeps, func(item *domain.SysUserDepartment) int64 {
return item.UserId
})
for i := range role.AuthUsers {
uid := role.AuthUsers[i].Id
list, ok := userDepsGroup[uid]
if !ok {
continue
}
for _, item := range list {
if department, _ := departmentLazyLoad.Load(l.ctx, conn, item.DepartmentId); department != nil {
role.AuthUsers[i].Departments = append(role.AuthUsers[i].Departments, types.Department{
Id: department.Id,
Name: department.Name,
})
}
}
}
}
for _, menuId := range dm.Menus {
if menu, _ := menuLazyLoad.Load(l.ctx, conn, menuId); menu != nil {
role.Menus = append(role.Menus, types.NewTypesMenu(menu))
}
}
for _, appId := range dm.Apps {
if app, _ := appLazyLoad.Load(l.ctx, conn, appId); app != nil {
role.Apps = append(role.Apps, types.NewTypesApp(app))
}
}
resp = &types.RoleGetResponse{
Role: role,
}
... ...
... ... @@ -2,6 +2,7 @@ package role
import (
"context"
"github.com/samber/lo"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
... ... @@ -53,20 +54,18 @@ func NewDomainSysRole(companyId int64, item types.Role) *domain.SysRole {
users := domain.Values(item.AuthUsers, func(item types.User) int64 {
return item.Id
})
if item.AuthRange == 0 {
if len(menus) == len(domain.DefaultMenus) {
item.AuthRange = domain.AuthRangeAll
} else {
item.AuthRange = domain.AuthRangePart
}
}
return &domain.SysRole{
apps := domain.Values(item.Apps, func(item types.App) int64 { return item.Id })
role := &domain.SysRole{
CompanyId: companyId,
Name: item.Name,
Menus: menus,
AuthUsers: users,
AuthRange: item.AuthRange,
//AuthRange: item.AuthRange,
Remark: item.Remark,
}
role.AddAuthRange(lo.Ternary(len(menus) == len(domain.DefaultMenus), domain.AuthRangeAllMenu, 0))
role.AddAuthRange(lo.Ternary(len(apps) == len(domain.DefaultApps), domain.AuthRangeAllApp, 0))
return role
}
func NewTypesSysRole(item *domain.SysRole) types.Role {
... ... @@ -75,5 +74,6 @@ func NewTypesSysRole(item *domain.SysRole) types.Role {
Name: item.Name,
AuthRange: item.AuthRange,
UpdatedAt: item.UpdatedAt,
Remark: item.Remark,
}
}
... ...
... ... @@ -39,6 +39,7 @@ func (l *SystemRoleSearchLogic) SystemRoleSearch(req *types.RoleSearchRequest) (
list := make([]types.Role, 0)
userLazyLoad := domain.NewLazyLoadService(l.svcCtx.UserRepository.FindOne)
menuLazyLoad := domain.NewLazyLoadService(domain.FineOneMenu)
appLazyLoad := domain.NewLazyLoadService(l.svcCtx.AppRepository.FindOne)
for i := range dms {
role := NewTypesSysRole(dms[i])
for j, userId := range dms[i].AuthUsers {
... ... @@ -55,6 +56,11 @@ func (l *SystemRoleSearchLogic) SystemRoleSearch(req *types.RoleSearchRequest) (
role.Menus = append(role.Menus, types.NewTypesMenu(menu))
}
}
for _, appId := range dms[i].Apps {
if app, _ := appLazyLoad.Load(l.ctx, conn, appId); app != nil {
role.Apps = append(role.Apps, types.NewTypesApp(app))
}
}
list = append(list, role)
}
resp = &types.RoleSearchResponse{
... ...
... ... @@ -2,6 +2,7 @@ package role
import (
"context"
"github.com/samber/lo"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
... ... @@ -29,9 +30,9 @@ func NewSystemRoleUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *
func (l *SystemRoleUpdateLogic) SystemRoleUpdate(req *types.RoleUpdateRequest) (resp *types.RoleUpdateResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dm *domain.SysRole
role *domain.SysRole
)
if dm, err = l.svcCtx.RoleRepository.FindOne(l.ctx, conn, req.Id); err != nil {
if role, err = l.svcCtx.RoleRepository.FindOne(l.ctx, conn, req.Id); err != nil {
return nil, xerr.NewErrMsgErr("不存在", err)
}
// 不可编辑判断
... ... @@ -43,22 +44,17 @@ func (l *SystemRoleUpdateLogic) SystemRoleUpdate(req *types.RoleUpdateRequest) (
users := domain.Values(req.Role.AuthUsers, func(item types.User) int64 {
return item.Id
})
dm.Name = req.Role.Name
dm.Menus = menus
dm.AuthUsers = users
if req.Role.AuthRange == 0 {
if len(menus) == len(domain.DefaultMenus) {
dm.AuthRange = domain.AuthRangeAll
} else {
dm.AuthRange = domain.AuthRangePart
}
} else {
dm.AuthRange = req.Role.AuthRange
}
apps := domain.Values(req.Role.Apps, func(item types.App) int64 { return item.Id })
role.Name = req.Role.Name
role.Menus = menus
role.AuthUsers = users
role.Apps = apps
role.Remark = req.Role.Remark
role.AddAuthRange(lo.Ternary(len(menus) == len(domain.DefaultMenus), domain.AuthRangeAllMenu, 0))
role.AddAuthRange(lo.Ternary(len(apps) == len(domain.DefaultApps), domain.AuthRangeAllApp, 0))
// 更新
if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
dm, err = l.svcCtx.RoleRepository.UpdateWithVersion(l.ctx, conn, dm)
role, err = l.svcCtx.RoleRepository.UpdateWithVersion(l.ctx, conn, role)
return err
}, true); err != nil {
return nil, xerr.NewErrMsg("更新失败")
... ...
package middleware
import "net/http"
import (
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"net/http"
)
type LoginStatusCheckMiddleware struct {
compareFunc func(int64, string) error
secret string
}
func NewLoginStatusCheckMiddleware() *LoginStatusCheckMiddleware {
return &LoginStatusCheckMiddleware{}
func NewLoginStatusCheckMiddleware(fn func(int64, string) error, secret string) *LoginStatusCheckMiddleware {
return &LoginStatusCheckMiddleware{compareFunc: fn}
}
func (m *LoginStatusCheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// TODO generate middleware implement function, delete after code implementation
// Passthrough to next handler if need
token := r.Header.Get("Authorization")
if len(token) < 6 {
httpx.ErrorCtx(r.Context(), w, xerr.NewCodeErr(xerr.TokenExpireError, nil))
return
}
token = token[6:]
if tmpCtx, err := contextdata.ParseToken(r.Context(), m.secret, token); err != nil {
httpx.ErrorCtx(r.Context(), w, xerr.NewCodeErr(xerr.TokenExpireError, nil))
return
} else {
userToken := contextdata.GetUserTokenFromCtx(tmpCtx)
if err = m.compareFunc(userToken.UserId, token); err != nil {
httpx.ErrorCtx(r.Context(), w, xerr.NewCodeErr(xerr.TokenExpireError, err))
return
}
}
next(w, r)
}
}
... ...
package svc
import (
"github.com/samber/lo"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/rest"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/config"
... ... @@ -26,6 +27,8 @@ type ServiceContext struct {
// 外部接口
SmsService smslib.SMSService
UserAuthService middleware.UserAuthService
// 数据仓储
UserRepository domain.SysUserRepository
CompanyRepository domain.SysCompanyRepository
... ... @@ -46,14 +49,15 @@ func NewServiceContext(c config.Config) *ServiceContext {
//apiAuth := authlib.ApiAuthService{
// Service: gateway.NewService(c.ApiAuth.Name, c.ApiAuth.Host, c.ApiAuth.Timeout),
//}
userAuthService := middleware.NewUserAuthService(redis, c.Name)
return &ServiceContext{
Config: c,
DB: db,
Redis: redis,
SmsService: smslib.SMSService{Service: gateway.NewService("短信服务", "https://sms.fjmaimaimai.com:9897", time.Second*5)},
//LoginStatusCheck: middleware.NewLoginStatusCheckMiddleware().Handle,
UserAuthService: userAuthService,
LoginStatusCheck: middleware.NewLoginStatusCheckMiddleware(lo.Ternary(c.CheckAuth, userAuthService.Compare, nil), c.SystemAuth.AccessSecret, c.CheckAuthProba).Handle,
LogRequest: middleware.NewLogRequestMiddleware(c.LogRequest).Handle,
UserRepository: repository.NewSysUserRepository(cache.NewCachedRepository(mlCache)),
CompanyRepository: repository.NewSysCompanyRepository(cache.NewCachedRepository(mlCache)),
... ...
... ... @@ -17,3 +17,11 @@ func NewTypesSystemAppItem(item *domain.SysApp, cp *domain.SysCompanyApp) System
Sort: cp.Sort,
}
}
func NewTypesApp(item *domain.SysApp) App {
return App{
Id: item.Id,
Name: item.Name,
Logo: item.Logo,
}
}
... ...
... ... @@ -2,10 +2,11 @@
package types
type User struct {
Id int64 `json:"id,optional"` // 用户ID
Name string `json:"name,optional"` // 用户名称
Phone string `json:"phone,optional,omitempty"` // 用户手机号
Avatar string `json:"avatar,optional,omitempty"` // 头像
Id int64 `json:"id,optional"` // 用户ID
Name string `json:"name,optional"` // 用户名称
Phone string `json:"phone,optional,omitempty"` // 用户手机号
Avatar string `json:"avatar,optional,omitempty"` // 头像
Departments []Department `json:"departments,optional,omitempty"` // 部门列表
}
type CompanyRegisterRequest struct {
... ... @@ -184,8 +185,10 @@ type Role struct {
Name string `json:"name,optional,omitempty"` // 角色名称
Menus []Menu `json:"menus,optional,omitempty"` // 菜单列表
AuthUsers []User `json:"users,optional,omitempty"` // 拥护该角色的用户列表 user_id 列表
AuthRange int `json:"authRange,optional,omitempty,option=0|1|2"` // 权限范围(1:全部权限 2:部分权限)
Apps []App `json:"apps,optional,omitempty"` // 应用列表
AuthRange int `json:"authRange,optional,omitempty,option=0|1|2"` // 权限范围(1:全部菜单 2:全部应用)
UpdatedAt int64 `json:"updatedAt,optional,omitempty"` // 更新时间
Remark string `json:"remark,optional,omitempty"` // 备注说明
}
type RoleGetRequest struct {
... ... @@ -247,6 +250,12 @@ type Menu struct {
Sort int64 `json:"sort,optional,omitempty"` // 排序
}
type App struct {
Id int64 `json:"id,optional,omitempty"` // 菜单ID
Name string `json:"name,optional,omitempty"` // 菜单名称
Logo string `json:"logo,optional,omitempty"` // 图标
}
type Group struct {
Id int64 `json:"id"` // 分组ID
Name string `json:"name"` // 分组名称
... ... @@ -288,13 +297,14 @@ type SystemAppItem struct {
VisibleUsers []int64 `json:"visibleUsers,omitempty"` // 可见的用户 所有用户:空 部分用户:用户ID列表
Sort int `json:"sort,omitempty"` // 排序
HasAuth bool `json:"hasAuth"` // true:用户有权限 false:用户无权限
Url string `json:"url,omitempty"` // 应用地址
}
type SystemAppSetConfigRequest struct {
AppId int64 `json:"id"` // 公司应用ID
VisibleFlag int `json:"visibleFlag"` // 1:全员可见 2:部分可见
VisibleUsers []int64 `json:"visibleUsers"` // 可见的用户 所有用户:空 部分用户:用户ID列表
VisibleDepartments []int64 `json:"visibleDepartments"` // 可见的部门 部门ID列表
AppId int64 `json:"id"` // 公司应用ID
VisibleFlag int `json:"visibleFlag"` // 1:全员可见 2:部分可见
VisibleUsers []int64 `json:"visibleUsers"` // 可见的用户 所有用户:空 部分用户:用户ID列表
VisibleDepartments []int64 `json:"visibleDepartments,optional"` // 可见的部门 部门ID列表
}
type SystemAppSetConfigResponse struct {
... ...
... ... @@ -18,6 +18,9 @@ service Core {
@doc "应用-设置配置"
@handler systemAppSetConfig
post /system/app/set_config (SystemAppSetConfigRequest) returns (SystemAppSetConfigResponse)
@doc "应用-列表"
@handler systemAppList
post /system/app/list (SystemAppSearchRequest) returns (SystemAppSearchResponse)
}
type (
... ... @@ -53,6 +56,7 @@ type (
VisibleUsers []int64 `json:"visibleUsers,omitempty"` // 可见的用户 所有用户:空 部分用户:用户ID列表
Sort int `json:"sort,omitempty"` // 排序
HasAuth bool `json:"hasAuth"` // true:用户有权限 false:用户无权限
Url string `json:"url,omitempty"` // 应用地址
}
)
... ... @@ -62,7 +66,7 @@ type(
AppId int64 `json:"id"` // 公司应用ID
VisibleFlag int `json:"visibleFlag"` // 1:全员可见 2:部分可见
VisibleUsers []int64 `json:"visibleUsers"` // 可见的用户 所有用户:空 部分用户:用户ID列表
VisibleDepartments []int64 `json:"visibleDepartments"` // 可见的部门 部门ID列表
VisibleDepartments []int64 `json:"visibleDepartments,optional"` // 可见的部门 部门ID列表
}
SystemAppSetConfigResponse{
SystemApp SystemAppItem `json:"app"`
... ...
... ... @@ -6,8 +6,10 @@ type(
Name string `json:"name,optional,omitempty"` // 角色名称
Menus []Menu `json:"menus,optional,omitempty"` // 菜单列表
AuthUsers []User `json:"users,optional,omitempty"` // 拥护该角色的用户列表 user_id 列表
AuthRange int `json:"authRange,optional,omitempty,option=0|1|2"` // 权限范围(1:全部权限 2:部分权限)
Apps []App `json:"apps,optional,omitempty"` // 应用列表
AuthRange int `json:"authRange,optional,omitempty,option=0|1|2"` // 权限范围(1:全部菜单 2:全部应用)
UpdatedAt int64 `json:"updatedAt,optional,omitempty"` // 更新时间
Remark string `json:"remark,optional,omitempty"` // 备注说明
}
)
... ... @@ -92,4 +94,9 @@ type(
Icon string `json:"icon,optional,omitempty"` // 图标
Sort int64 `json:"sort,optional,omitempty"` // 排序
}
App{
Id int64 `json:"id,optional,omitempty"` // 菜单ID
Name string `json:"name,optional,omitempty"` // 菜单名称
Logo string `json:"logo,optional,omitempty"` // 图标
}
)
\ No newline at end of file
... ...
... ... @@ -27,7 +27,7 @@ service Core {
@server(
prefix: v1
group: auth
middleware: LogRequest
middleware: LogRequest,LoginStatusCheck
jwt: SystemAuth
)
service Core {
... ... @@ -63,10 +63,11 @@ service Core {
type(
User{
Id int64 `json:"id,optional"` // 用户ID
Name string `json:"name,optional"` // 用户名称
Phone string `json:"phone,optional,omitempty"` // 用户手机号
Avatar string `json:"avatar,optional,omitempty"`// 头像
Id int64 `json:"id,optional"` // 用户ID
Name string `json:"name,optional"` // 用户名称
Phone string `json:"phone,optional,omitempty"` // 用户手机号
Avatar string `json:"avatar,optional,omitempty"` // 头像
Departments []Department `json:"departments,optional,omitempty"` // 部门列表
}
)
... ...
syntax = "v1"
info(
title: "xx实例"
desc: "xx实例"
author: "author"
email: "email"
version: "v1"
)
@server(
prefix: v1
group: sys_employee
jwt: JwtAuth
)
service Core {
@doc "详情"
@handler sys_employeeGet
get /sys_employee/:id (SysEmployeeGetRequest) returns (SysEmployeeGetResponse)
@doc "保存"
@handler sys_employeeSave
post /sys_employee (SysEmployeeSaveRequest) returns (SysEmployeeSaveResponse)
@doc "删除"
@handler sys_employeeDelete
delete /sys_employee/:id (SysEmployeeDeleteRequest) returns (SysEmployeeDeleteResponse)
@doc "更新"
@handler sys_employeeUpdate
put /sys_employee/:id (SysEmployeeUpdateRequest) returns (SysEmployeeUpdateResponse)
@doc "搜索"
@handler sys_employeeSearch
post /sys_employee/search (SysEmployeeSearchRequest) returns (SysEmployeeSearchResponse)
}
type (
SysEmployeeGetRequest {
Id int64 `path:"id"`
}
SysEmployeeGetResponse struct{
SysEmployee SysEmployeeItem `json:"sys_employee"`
}
SysEmployeeSaveRequest struct{
SysEmployee SysEmployeeItem `json:"sys_employee"`
}
SysEmployeeSaveResponse struct{}
SysEmployeeDeleteRequest struct{
Id int64 `path:"id"`
}
SysEmployeeDeleteResponse struct{}
SysEmployeeUpdateRequest struct{
Id int64 `path:"id"`
SysEmployee SysEmployeeItem `json:"sys_employee"`
}
SysEmployeeUpdateResponse struct{}
SysEmployeeSearchRequest struct{
Page int `json:"page"`
Size int `json:"size"`
}
SysEmployeeSearchResponse{
List []SysEmployeeItem `json:"list"`
Total int64 `json:"total"`
}
SysEmployeeItem struct{
}
)
// logic CRUD
// Save
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.SysEmployee
//)
//// 唯一判断
//dm = NewDomainSysEmployee(req.SysEmployee)
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.SysEmployeeRepository.Insert(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("保存失败")
//}
////resp = &types.SysEmployeeSaveResponse{}
//return
//func NewDomainSysEmployee(item types.SysEmployeeItem) *domain.SysEmployee {
// return &domain.SysEmployee{
// }
//}
//
//func NewTypesSysEmployee(item *domain.SysEmployee) types.SysEmployeeItem {
// return types.SysEmployeeItem{
// Id: item.Id,
// }
//}
// Get
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.SysEmployee
//)
//// 货号唯一
//if dm, err = l.svcCtx.SysEmployeeRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//resp = &types.SysEmployeeGetResponse{
// SysEmployee: NewTypesSysEmployee(dm),
//}
//return
// Delete
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.SysEmployee
//)
//if dm, err = l.svcCtx.SysEmployeeRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// if dm, err = l.svcCtx.SysEmployeeRepository.Delete(l.ctx, conn, dm); err != nil {
// return err
// }
// return nil
//}, true); err != nil {
// return nil, xerr.NewErrMsgErr("移除失败", err)
//}
//return
// Search
//var (
// conn = l.svcCtx.DefaultDBConn()
// dms []*domain.SysEmployee
// total int64
//)
//
//queryOptions := domain.NewQueryOptions().WithOffsetLimit(req.Page, req.Size).
// WithKV("", "")
//total, dms, err = l.svcCtx.SysEmployeeRepository.Find(l.ctx, conn, queryOptions)
//list := make([]types.SysEmployeeItem, 0)
//for i := range dms {
// list = append(list, NewTypesSysEmployee(dms[i]))
//}
//resp = &types.SysEmployeeSearchResponse{
// List: list,
// Total: total,
//}
//return
// Update
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.SysEmployee
//)
//if dm, err = l.svcCtx.SysEmployeeRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//// 不可编辑判断
//// 赋值
//// 更新
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.SysEmployeeRepository.UpdateWithVersion(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("更新失败")
//}
//resp = &types.SysEmployeeUpdateResponse{}
//return
... ... @@ -17,6 +17,7 @@ type SysApp struct {
Type string // 分类 default
VersionNumber string // 应用版本号
Status int // 1:启用、2:停用
Url string
CreatedAt int64
UpdatedAt int64
DeletedAt int64
... ...
... ... @@ -12,8 +12,10 @@ type SysRole struct {
CompanyId int64 // 公司ID
Name string // 公司名称
Menus []int64 `gorm:"type:jsonb;serializer:json"` // 菜单列表
Apps []int64 `gorm:"type:jsonb;serializer:json"` // 应用列表
AuthUsers []int64 `gorm:"type:jsonb;serializer:json"` // 拥护该角色的用户列表
AuthRange int
Remark string
CreatedAt int64
UpdatedAt int64
DeletedAt int64
... ...
... ... @@ -19,10 +19,11 @@ type SysApp struct {
//VisibleGroups []int64 `json:",omitempty"` // 可见的用户组 所有用户:空 部分用户:用户ID列表
//AppConfig AppConfig `json:",omitempty"` // 应用配置
//Sort int `json:",omitempty"` // 排序
CreatedAt int64 `json:",omitempty"`
UpdatedAt int64 `json:",omitempty"`
DeletedAt int64 `json:",omitempty"`
Version int `json:",omitempty"`
Url string `json:",omitempty"` // 应用地址
CreatedAt int64 `json:",omitempty"`
UpdatedAt int64 `json:",omitempty"`
DeletedAt int64 `json:",omitempty"`
Version int `json:",omitempty"`
}
type SysAppRepository interface {
... ...
... ... @@ -11,8 +11,10 @@ type SysRole struct {
CompanyId int64 `json:"companyId"` // 公司ID
Name string `json:",omitempty"` // 角色名称
Menus []int64 `json:",omitempty"` // 菜单列表
Apps []int64 `json:",omitempty"` // 应用列表
AuthUsers []int64 `json:",omitempty"` // 拥护该角色的用户列表
AuthRange int `json:",omitempty"` // 权限范围(1:全部权限 2:部分权限)
Remark string `json:",omitempty"` // 备注说明
CreatedAt int64 `json:",omitempty"`
UpdatedAt int64 `json:",omitempty"`
DeletedAt int64 `json:",omitempty"`
... ... @@ -46,6 +48,18 @@ func (role *SysRole) RemoveUser(userId int64) {
role.AuthUsers = lo.Without(role.AuthUsers, userId)
}
func (role *SysRole) AddAuthRange(auth int) {
if auth == 0 {
return
}
if !(auth == AuthRangeAllMenu || auth == AuthRangeAllApp) {
return
}
if role.AuthRange&auth == 0 {
role.AuthRange |= auth
}
}
type SysMenu struct {
Id int64 `json:"id,omitempty"` // 菜单ID
ParentId int64 `json:"parentId"` // 父级ID
... ... @@ -60,8 +74,8 @@ type SysMenu struct {
}
const (
AuthRangeAll = 1 // 全部权限
AuthRangePart = 2 // 部分权限
AuthRangeAllMenu = 1 // 全部菜单权限
AuthRangeAllApp = 2 // 全部APP权限
)
var DefaultMenus []*SysMenu = []*SysMenu{
... ...
package middleware
import (
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/tool"
)
type UserAuthService struct {
redis *redis.Redis
appName string
checkAuth bool
}
func NewUserAuthService(redis *redis.Redis, appName string) UserAuthService {
return UserAuthService{
redis: redis,
appName: appName,
}
}
// Refresh 刷新缓存的User Token
func (l UserAuthService) Refresh(userId int64, token string) error {
err := l.redis.Set(l.CacheKey(userId), l.Hash(token))
if err != nil {
return err
}
return nil
}
// Compare 比较当前的Token是否已经过期
func (l UserAuthService) Compare(userId int64, token string) error {
ok, err := l.redis.Exists(l.CacheKey(userId))
if err != nil {
return err
}
if !ok {
return errors.New("Token not exists.") //l.Refresh(userId, token)
}
cacheToken, err := l.redis.Get(l.CacheKey(userId))
if err != nil {
return err
}
if !l.compare(cacheToken, token) {
return errors.New("Token is expired.")
}
return nil
}
func (l UserAuthService) compare(cacheToken, token string) bool {
if len(cacheToken) == len(token) && cacheToken == token {
return true
}
if cacheToken == l.Hash(token) {
return true
}
return false
}
// Hash token哈希编码
func (l UserAuthService) Hash(token string) string {
return tool.Md5ByString(token)
}
func (l UserAuthService) CacheKey(userId int64) string {
return fmt.Sprintf("%v:cache:%v:id:%v", l.appName, "user.auth", userId)
}
... ...
package middleware
import (
"github.com/zeromicro/go-zero/core/mathx"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"net/http"
)
type LoginStatusCheckMiddleware struct {
compareFunc func(int64, string) error
secret string
proba *mathx.Proba
kProba float64
}
// NewLoginStatusCheckMiddleware 登录状态验证,kProba代表验证token的概率,需要小于1,越小校验的概率越低(不需要每次接口调用都验证)
func NewLoginStatusCheckMiddleware(fn func(int64, string) error, secret string, kProba float64) *LoginStatusCheckMiddleware {
return &LoginStatusCheckMiddleware{
compareFunc: fn,
secret: secret,
proba: mathx.NewProba(),
kProba: kProba,
}
}
func (m *LoginStatusCheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if m.compareFunc == nil {
return
}
token := r.Header.Get("Authorization")
if len(token) < 7 {
//httpx.ErrorCtx(r.Context(), w, xerr.NewCodeErr(xerr.TokenExpireError, nil))
httpx.WriteJson(w, http.StatusUnauthorized, xerr.Error(xerr.TokenExpireError, ""))
return
}
token = token[7:]
if tmpCtx, err := contextdata.ParseToken(r.Context(), m.secret, token); err != nil {
httpx.WriteJson(w, http.StatusUnauthorized, xerr.Error(xerr.TokenExpireError, ""))
return
} else {
if m.proba.TrueOnProba(m.kProba) {
userToken := contextdata.GetUserTokenFromCtx(tmpCtx)
if err = m.compareFunc(userToken.UserId, token); err != nil {
httpx.WriteJson(w, http.StatusUnauthorized, xerr.Error(xerr.TokenExpireError, err.Error()))
return
}
}
}
next(w, r)
}
}
... ...
... ... @@ -2,20 +2,23 @@ package tool
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
)
/** 加密方式 **/
func Md5ByString(str string) string {
m := md5.New()
_, err := io.WriteString(m, str)
if err != nil {
panic(err)
}
arr := m.Sum(nil)
return fmt.Sprintf("%x", arr)
//m := md5.New()
//_, err := io.WriteString(m, str)
//if err != nil {
// panic(err)
//}
//arr := m.Sum(nil)
//return fmt.Sprintf("%x", arr)
sum := md5.Sum([]byte(str))
return hex.EncodeToString(sum[:])
}
func Md5ByBytes(b []byte) string {
... ...