package auth import ( "git.sxidc.com/go-framework/baize/convenient/domain/auth/jwt_tools" "git.sxidc.com/go-framework/baize/convenient/domain/auth/permission" "git.sxidc.com/go-framework/baize/convenient/domain/auth/permission_group" "git.sxidc.com/go-framework/baize/convenient/domain/auth/relations" "git.sxidc.com/go-framework/baize/convenient/domain/auth/role" "git.sxidc.com/go-framework/baize/convenient/domain/auth/user" "git.sxidc.com/go-framework/baize/framework/binding" "git.sxidc.com/go-framework/baize/framework/core/api" "git.sxidc.com/go-framework/baize/framework/core/api/request" "git.sxidc.com/go-framework/baize/framework/core/api/response" "git.sxidc.com/go-framework/baize/framework/core/application" "git.sxidc.com/go-framework/baize/framework/core/domain" "git.sxidc.com/go-framework/baize/framework/core/domain/entity" "git.sxidc.com/go-framework/baize/framework/core/infrastructure" "git.sxidc.com/go-framework/baize/framework/core/infrastructure/database" "git.sxidc.com/go-framework/baize/framework/core/infrastructure/database/sql" "git.sxidc.com/go-tools/utils/encoding" "git.sxidc.com/go-tools/utils/strutils" "github.com/pkg/errors" "net/http" "time" ) // Simple Bind参数 type Simple struct { // schema Schema string // AES加密用到的Key AESKey string // JWT的Key JWTSecretKey string // JWT到期时间 JWTExpiredSec int64 // 鉴权中间件 AuthMiddleware binding.Middleware // 管理员用户密码 AdminUserPassword string } const ( adminUserName = "admin" adminRoleName = "管理员" ) var permissionGroups = map[string][][]string{ "权限管理": { {"创建权限", "/permission/create", http.MethodPost}, {"删除权限", "/permission/delete", http.MethodDelete}, {"修改权限", "/permission/update", http.MethodPut}, {"查询权限", "/permission/query", http.MethodGet}, {"根据ID获取权限", "/permission/get", http.MethodGet}, {"更新权限的权限组", "/permission/permissionGroup/update", http.MethodPost}, {"查询权限的权限组", "/permission/permissionGroup/query", http.MethodGet}, }, "权限组管理": { {"创建权限组", "/permissionGroup/create", http.MethodPost}, {"删除权限组", "/permissionGroup/delete", http.MethodDelete}, {"修改权限组", "/permissionGroup/update", http.MethodPut}, {"查询权限组", "/permissionGroup/query", http.MethodGet}, {"根据ID获取权限组", "/permissionGroup/get", http.MethodGet}, {"更新权限组的权限", "/permissionGroup/permission/update", http.MethodPost}, {"查询权限组的权限", "/permissionGroup/permission/query", http.MethodGet}, {"更新权限的角色", "/permission/role/update", http.MethodPost}, {"查询权限的角色", "/permission/role/query", http.MethodGet}, }, "角色管理": { {"创建角色", "/role/create", http.MethodPost}, {"删除角色", "/role/delete", http.MethodDelete}, {"修改角色", "/role/update", http.MethodPut}, {"查询角色", "/role/query", http.MethodGet}, {"根据ID获取角色", "/role/get", http.MethodGet}, {"更新角色的权限", "/role/permission/update", http.MethodPost}, {"查询角色的权限", "/role/permission/query", http.MethodGet}, {"更新角色的用户", "/role/user/update", http.MethodPost}, {"查询角色的用户", "/role/user/query", http.MethodGet}, }, "用户管理": { {"创建用户", "/user/create", http.MethodPost}, {"删除用户", "/user/delete", http.MethodDelete}, {"修改用户", "/user/update", http.MethodPut}, {"查询用户", "/user/query", http.MethodGet}, {"根据ID获取用户", "/user/get", http.MethodGet}, {"更新用户的角色", "/user/role/update", http.MethodPost}, {"查询用户的角色", "/user/role/query", http.MethodGet}, }, "Token管理": { {"注销", "/logout", http.MethodPost}, {"Challenge", "/challenge", http.MethodPost}, }, } func (simple *Simple) init(urlPrefix string, i *infrastructure.Infrastructure) { dbExecutor := i.DBExecutor() adminUserExist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{ TableName: domain.TableName(simple.Schema, &user.Entity{}), Conditions: sql.NewConditions().Equal(user.ColumnUserName, adminUserName), }) if err != nil { panic(err) } if adminUserExist { return } adminUserID := strutils.SimpleUUID() adminRoleID := strutils.SimpleUUID() permissionGroupEntities := make([]permission_group.Entity, 0) permissionEntities := make([]permission.Entity, 0) permissionIDs := make([]string, 0) permissionInGroup := make(map[string][]string) for permissionGroupName, permissions := range permissionGroups { permissionInGroupIDs := make([]string, 0) for _, perm := range permissions { permissionID := strutils.SimpleUUID() permissionInGroupIDs = append(permissionInGroupIDs, permissionID) permissionEntities = append(permissionEntities, permission.Entity{ Base: entity.Base{ID: permissionID}, Name: perm[0], Description: perm[0], Resource: urlPrefix + perm[1], Action: perm[2], UserIDFields: entity.UserIDFields{ CreateUserID: adminUserID, LastUpdateUserID: adminUserID, }, }) } permissionIDs = append(permissionIDs, permissionInGroupIDs...) permissionGroupID := strutils.SimpleUUID() permissionInGroup[permissionGroupID] = permissionInGroupIDs permissionGroupEntities = append(permissionGroupEntities, permission_group.Entity{ Base: entity.Base{ID: permissionGroupID}, Name: permissionGroupName, Description: permissionGroupName, UserIDFields: entity.UserIDFields{ CreateUserID: adminUserID, LastUpdateUserID: adminUserID, }, }) } encryptedAdminUserPassword, err := encoding.AESEncrypt(simple.AdminUserPassword, simple.AESKey) if err != nil { panic(err) } adminUserEntity := &user.Entity{ Base: entity.Base{ID: adminUserID}, UserName: adminUserName, Password: encryptedAdminUserPassword, Name: adminUserName, } adminRoleEntity := &role.Entity{ Base: entity.Base{ID: adminRoleID}, Name: adminRoleName, Description: adminRoleName, UserIDs: []string{adminUserID}, UserIDFields: entity.UserIDFields{ CreateUserID: adminUserID, LastUpdateUserID: adminUserID, }, } err = database.Transaction(dbExecutor, func(tx database.Executor) error { // 创建权限 err := database.InsertEntity(tx, domain.TableName(simple.Schema, &permission.Entity{}), permissionEntities) if err != nil { return err } // 创建权限组 err = database.InsertEntity(tx, domain.TableName(simple.Schema, &permission_group.Entity{}), permissionGroupEntities) if err != nil { return err } // 创建管理员角色 err = database.InsertEntity(tx, domain.TableName(simple.Schema, &role.Entity{}), adminRoleEntity) if err != nil { return err } // 创建管理员用户 err = database.InsertEntity(tx, domain.TableName(simple.Schema, &user.Entity{}), adminUserEntity) if err != nil { return err } // 关联权限组和权限 permissionGroupAndPermissionTableRows := make([]sql.TableRow, 0) for permissionGroupID, permissionInGroupIDs := range permissionInGroup { for _, permissionInGroupID := range permissionInGroupIDs { tableRow := sql.NewTableRow(). Add(domain.RelationColumnName(&permission_group.Entity{}), permissionGroupID). Add(domain.RelationColumnName(&permission.Entity{}), permissionInGroupID) permissionGroupAndPermissionTableRows = append(permissionGroupAndPermissionTableRows, *tableRow) } } err = database.InsertBatch(tx, &sql.InsertBatchExecuteParams{ TableName: domain.RelationTableName(simple.Schema, &permission_group.Entity{}, &permission.Entity{}), TableRowBatch: permissionGroupAndPermissionTableRows, }) if err != nil { return err } // 关联管理员角色和权限 roleAndPermissionTableRows := make([]sql.TableRow, 0) for _, permissionID := range permissionIDs { tableRow := sql.NewTableRow(). Add(domain.RelationColumnName(&role.Entity{}), adminRoleID). Add(domain.RelationColumnName(&permission.Entity{}), permissionID) roleAndPermissionTableRows = append(roleAndPermissionTableRows, *tableRow) } err = database.InsertBatch(tx, &sql.InsertBatchExecuteParams{ TableName: domain.RelationTableName(simple.Schema, &role.Entity{}, &permission.Entity{}), TableRowBatch: roleAndPermissionTableRows, }) if err != nil { return err } // 关联管理员用户和管理员角色 err = database.Insert(tx, &sql.InsertExecuteParams{ TableName: domain.RelationTableName(simple.Schema, &user.Entity{}, &role.Entity{}), TableRow: sql.NewTableRow(). Add(domain.RelationColumnName(&user.Entity{}), adminUserID). Add(domain.RelationColumnName(&role.Entity{}), adminRoleID), }) if err != nil { return err } return nil }) if err != nil { panic(err) } } func (simple *Simple) bind(binder *binding.Binder) { (&permission.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder) (&permission_group.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder) (&role.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder) (&user.Simple{Schema: simple.Schema, AESKey: simple.AESKey, AuthMiddleware: simple.AuthMiddleware}).Bind(binder) (&relations.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder) // 登录 binding.PostBind(binder, &binding.SimpleBindItem[map[string]any]{ Path: "/login", SendResponseFunc: response.SendMapResponse, RequestParams: &LoginJsonBody{}, ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (map[string]any, error) { errResponse := map[string]any{ "token": "", } jsonBody, err := request.ToConcrete[*LoginJsonBody](params) if err != nil { return errResponse, err } encryptedPassword, err := encoding.AESEncrypt(jsonBody.Password, simple.AESKey) if err != nil { return errResponse, errors.New(err.Error()) } userTableName := domain.TableName(simple.Schema, &user.Entity{}) dbExecutor := i.DBExecutor() result, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{ TableName: userTableName, Conditions: sql.NewConditions(). Equal(user.ColumnUserName, jsonBody.UserName). Equal(user.ColumnPassword, encryptedPassword), }) if err != nil { if database.IsErrorDBRecordNotExist(err) { return errResponse, errors.New("用户名或密码错误") } return errResponse, errors.New(err.Error()) } existUser := new(user.Entity) err = sql.ParseSqlResult(result, existUser) if err != nil { return errResponse, err } token, err := jwt_tools.NewJWT(simple.JWTSecretKey, existUser.ID, simple.JWTExpiredSec) if err != nil { return errResponse, errors.New(err.Error()) } err = database.Update(dbExecutor, &sql.UpdateExecuteParams{ TableName: userTableName, TableRow: sql.NewTableRow().Add(user.ColumnToken, token). Add(user.ColumnLastLoginTime, time.Now().Local()), Conditions: sql.NewConditions().Equal(entity.ColumnID, existUser.ID), }) if err != nil { return errResponse, errors.New(err.Error()) } return map[string]any{ "token": token, }, nil }, }) // 注销 binding.PostBind(binder, &binding.SimpleBindItem[any]{ Path: "/logout", SendResponseFunc: response.SendMsgResponse, ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) { userInfo := c.GetUserInfo() userTableName := domain.TableName(simple.Schema, &user.Entity{}) dbExecutor := i.DBExecutor() err := database.Update(dbExecutor, &sql.UpdateExecuteParams{ TableName: userTableName, TableRow: sql.NewTableRow().Add(user.ColumnToken, ""), Conditions: sql.NewConditions().Equal(entity.ColumnID, userInfo.GetID()), }) if err != nil { return nil, errors.New(err.Error()) } return nil, nil }, }, simple.AuthMiddleware) // Challenge binding.PostBind(binder, &binding.SimpleBindItem[UserWithRoleInfo]{ Path: "/challenge", SendResponseFunc: response.SendInfoResponse[UserWithRoleInfo], ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (UserWithRoleInfo, error) { errInfo := UserWithRoleInfo{ RoleInfos: make([]role.Info, 0), } userInfo := c.GetUserInfo() userAndRoleTableName := domain.RelationTableName(simple.Schema, &user.Entity{}, &role.Entity{}) roleTableName := domain.TableName(simple.Schema, &role.Entity{}) dbExecutor := i.DBExecutor() roleIDResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{ TableName: userAndRoleTableName, SelectClauses: []string{domain.RelationColumnName(&role.Entity{})}, Conditions: sql.NewConditions().Equal(domain.RelationColumnName(&user.Entity{}), userInfo.GetID()), PageNo: 0, PageSize: 0, }) if err != nil { return errInfo, errors.New(err.Error()) } if totalCount == 0 { return UserWithRoleInfo{ UserInfo: *(userInfo.(*user.Info)), RoleInfos: make([]role.Info, 0), }, nil } roleIDs := make([]string, 0) err = sql.ParseSqlResult(roleIDResults, &roleIDs) if err != nil { return errInfo, errors.New(err.Error()) } roleResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{ TableName: roleTableName, Conditions: sql.NewConditions().In(entity.ColumnID, roleIDs), PageNo: 0, PageSize: 0, }) if err != nil { return errInfo, errors.New(err.Error()) } if totalCount == 0 { return UserWithRoleInfo{ UserInfo: *(userInfo.(*user.Info)), RoleInfos: make([]role.Info, 0), }, nil } roleInfos := make([]role.Info, 0) err = sql.ParseSqlResult(roleResults, &roleInfos) if err != nil { return errInfo, errors.New(err.Error()) } return UserWithRoleInfo{ UserInfo: *(userInfo.(*user.Info)), RoleInfos: roleInfos, }, nil }, }, simple.AuthMiddleware) } func BindAuth(app *application.App, simple *Simple) { prefixRootRouter := app.ChooseRouter(api.RouterPrefix, "") binder := binding.NewBinder(prefixRootRouter, app.Infrastructure()) simple.init(prefixRootRouter.BasePath(), app.Infrastructure()) simple.bind(binder) }