auth.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. package auth
  2. import (
  3. "git.sxidc.com/go-framework/baize/convenient/domain/auth/jwt_tools"
  4. "git.sxidc.com/go-framework/baize/convenient/domain/auth/permission"
  5. "git.sxidc.com/go-framework/baize/convenient/domain/auth/permission_group"
  6. "git.sxidc.com/go-framework/baize/convenient/domain/auth/relations"
  7. "git.sxidc.com/go-framework/baize/convenient/domain/auth/role"
  8. "git.sxidc.com/go-framework/baize/convenient/domain/auth/user"
  9. "git.sxidc.com/go-framework/baize/framework/binding"
  10. "git.sxidc.com/go-framework/baize/framework/core/api"
  11. "git.sxidc.com/go-framework/baize/framework/core/api/request"
  12. "git.sxidc.com/go-framework/baize/framework/core/api/response"
  13. "git.sxidc.com/go-framework/baize/framework/core/application"
  14. "git.sxidc.com/go-framework/baize/framework/core/domain"
  15. "git.sxidc.com/go-framework/baize/framework/core/domain/entity"
  16. "git.sxidc.com/go-framework/baize/framework/core/infrastructure"
  17. "git.sxidc.com/go-framework/baize/framework/core/infrastructure/database"
  18. "git.sxidc.com/go-framework/baize/framework/core/infrastructure/database/sql"
  19. "git.sxidc.com/go-tools/utils/encoding"
  20. "git.sxidc.com/go-tools/utils/strutils"
  21. "github.com/pkg/errors"
  22. "net/http"
  23. "time"
  24. )
  25. // Simple Bind参数
  26. type Simple struct {
  27. // schema
  28. Schema string
  29. // AES加密用到的Key
  30. AESKey string
  31. // JWT的Key
  32. JWTSecretKey string
  33. // JWT到期时间
  34. JWTExpiredSec int64
  35. // 鉴权中间件
  36. AuthMiddleware binding.Middleware
  37. // 管理员用户密码
  38. AdminUserPassword string
  39. }
  40. const (
  41. adminUserName = "admin"
  42. adminRoleName = "管理员"
  43. )
  44. var permissionGroups = map[string][][]string{
  45. "权限管理": {
  46. {"创建权限", "/permission/create", http.MethodPost},
  47. {"删除权限", "/permission/delete", http.MethodDelete},
  48. {"修改权限", "/permission/update", http.MethodPut},
  49. {"查询权限", "/permission/query", http.MethodGet},
  50. {"根据ID获取权限", "/permission/get", http.MethodGet},
  51. {"更新权限的权限组", "/permission/permissionGroup/update", http.MethodPost},
  52. {"查询权限的权限组", "/permission/permissionGroup/query", http.MethodGet},
  53. },
  54. "权限组管理": {
  55. {"创建权限组", "/permissionGroup/create", http.MethodPost},
  56. {"删除权限组", "/permissionGroup/delete", http.MethodDelete},
  57. {"修改权限组", "/permissionGroup/update", http.MethodPut},
  58. {"查询权限组", "/permissionGroup/query", http.MethodGet},
  59. {"根据ID获取权限组", "/permissionGroup/get", http.MethodGet},
  60. {"更新权限组的权限", "/permissionGroup/permission/update", http.MethodPost},
  61. {"查询权限组的权限", "/permissionGroup/permission/query", http.MethodGet},
  62. {"更新权限的角色", "/permission/role/update", http.MethodPost},
  63. {"查询权限的角色", "/permission/role/query", http.MethodGet},
  64. },
  65. "角色管理": {
  66. {"创建角色", "/role/create", http.MethodPost},
  67. {"删除角色", "/role/delete", http.MethodDelete},
  68. {"修改角色", "/role/update", http.MethodPut},
  69. {"查询角色", "/role/query", http.MethodGet},
  70. {"根据ID获取角色", "/role/get", http.MethodGet},
  71. {"更新角色的权限", "/role/permission/update", http.MethodPost},
  72. {"查询角色的权限", "/role/permission/query", http.MethodGet},
  73. {"更新角色的用户", "/role/user/update", http.MethodPost},
  74. {"查询角色的用户", "/role/user/query", http.MethodGet},
  75. },
  76. "用户管理": {
  77. {"创建用户", "/user/create", http.MethodPost},
  78. {"删除用户", "/user/delete", http.MethodDelete},
  79. {"修改用户", "/user/update", http.MethodPut},
  80. {"查询用户", "/user/query", http.MethodGet},
  81. {"根据ID获取用户", "/user/get", http.MethodGet},
  82. {"更新用户的角色", "/user/role/update", http.MethodPost},
  83. {"查询用户的角色", "/user/role/query", http.MethodGet},
  84. },
  85. "Token管理": {
  86. {"注销", "/logout", http.MethodPost},
  87. {"Challenge", "/challenge", http.MethodPost},
  88. },
  89. }
  90. func (simple *Simple) init(i *infrastructure.Infrastructure) {
  91. dbExecutor := i.DBExecutor()
  92. adminUserExist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
  93. TableName: domain.TableName(simple.Schema, &user.Entity{}),
  94. Conditions: sql.NewConditions().Equal(user.ColumnUserName, adminUserName),
  95. })
  96. if err != nil {
  97. panic(err)
  98. }
  99. if adminUserExist {
  100. return
  101. }
  102. adminUserID := strutils.SimpleUUID()
  103. adminRoleID := strutils.SimpleUUID()
  104. permissionGroupEntities := make([]any, 0)
  105. permissionEntities := make([]any, 0)
  106. permissionGroupIDs := make([]string, 0)
  107. permissionIDs := make([]string, 0)
  108. for permissionGroupName, permissions := range permissionGroups {
  109. permissionInGroupIDs := make([]string, 0)
  110. for _, perm := range permissions {
  111. permissionID := strutils.SimpleUUID()
  112. permissionInGroupIDs = append(permissionInGroupIDs, permissionID)
  113. permissionEntities = append(permissionEntities, permission.Entity{
  114. Base: entity.Base{ID: permissionID},
  115. Name: perm[0],
  116. Description: perm[0],
  117. Resource: perm[1],
  118. Action: perm[2],
  119. UserIDFields: entity.UserIDFields{CreateUserID: adminUserID},
  120. })
  121. }
  122. permissionIDs = append(permissionIDs, permissionInGroupIDs...)
  123. permissionGroupID := strutils.SimpleUUID()
  124. permissionGroupIDs = append(permissionGroupIDs, permissionGroupID)
  125. permissionGroupEntities = append(permissionGroupEntities, permission_group.Entity{
  126. Base: entity.Base{ID: permissionGroupID},
  127. Name: permissionGroupName,
  128. Description: permissionGroupName,
  129. PermissionIDs: permissionInGroupIDs,
  130. UserIDFields: entity.UserIDFields{CreateUserID: adminUserID},
  131. })
  132. }
  133. encryptedAdminUserPassword, err := encoding.AESEncrypt(simple.AdminUserPassword, simple.AESKey)
  134. if err != nil {
  135. panic(err)
  136. }
  137. adminUserEntity := &user.Entity{
  138. Base: entity.Base{ID: adminUserID},
  139. UserName: adminUserName,
  140. Password: encryptedAdminUserPassword,
  141. Name: adminUserName,
  142. RoleIDs: []string{adminRoleID},
  143. }
  144. adminRoleEntity := &role.Entity{
  145. Base: entity.Base{ID: adminRoleID},
  146. Name: adminRoleName,
  147. Description: adminRoleName,
  148. UserIDs: []string{adminUserID},
  149. PermissionIDs: permissionIDs,
  150. UserIDFields: entity.UserIDFields{CreateUserID: adminUserID},
  151. }
  152. err = database.Transaction(dbExecutor, func(tx database.Executor) error {
  153. // 创建权限
  154. err := database.InsertEntityBatch(tx, domain.TableName(simple.Schema, &permission.Entity{}), permissionEntities)
  155. if err != nil {
  156. return err
  157. }
  158. // 创建权限组
  159. err = database.InsertEntityBatch(tx, domain.TableName(simple.Schema, &permission_group.Entity{}), permissionGroupEntities)
  160. if err != nil {
  161. return err
  162. }
  163. // 创建管理员角色
  164. err = database.InsertEntity(tx, domain.TableName(simple.Schema, &role.Entity{}), adminRoleEntity)
  165. if err != nil {
  166. return err
  167. }
  168. // 创建管理员用户
  169. err = database.InsertEntity(tx, domain.TableName(simple.Schema, &user.Entity{}), adminUserEntity)
  170. if err != nil {
  171. return err
  172. }
  173. return nil
  174. })
  175. if err != nil {
  176. panic(err)
  177. }
  178. }
  179. func (simple *Simple) bind(binder *binding.Binder) {
  180. (&permission.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  181. (&permission_group.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  182. (&role.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  183. (&user.Simple{Schema: simple.Schema, AESKey: simple.AESKey, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  184. (&relations.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  185. // 登录
  186. binding.PostBind(binder, &binding.SimpleBindItem[map[string]any]{
  187. Path: "/login",
  188. SendResponseFunc: response.SendMapResponse,
  189. RequestParams: &LoginJsonBody{},
  190. ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (map[string]any, error) {
  191. errResponse := map[string]any{
  192. "token": "",
  193. }
  194. jsonBody, err := request.ToConcrete[*LoginJsonBody](params)
  195. if err != nil {
  196. return errResponse, err
  197. }
  198. encryptedPassword, err := encoding.AESEncrypt(jsonBody.Password, simple.AESKey)
  199. if err != nil {
  200. return errResponse, errors.New(err.Error())
  201. }
  202. userTableName := domain.TableName(simple.Schema, &user.Entity{})
  203. dbExecutor := i.DBExecutor()
  204. result, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{
  205. TableName: userTableName,
  206. Conditions: sql.NewConditions().
  207. Equal(user.ColumnUserName, jsonBody.UserName).
  208. Equal(user.ColumnPassword, encryptedPassword),
  209. })
  210. if err != nil {
  211. if database.IsErrorDBRecordNotExist(err) {
  212. return errResponse, errors.New("用户名或密码错误")
  213. }
  214. return errResponse, errors.New(err.Error())
  215. }
  216. existUser := new(user.Entity)
  217. err = sql.ParseSqlResult(result, existUser)
  218. if err != nil {
  219. return errResponse, err
  220. }
  221. token, err := jwt_tools.NewJWT(simple.JWTSecretKey, existUser.ID, simple.JWTExpiredSec)
  222. if err != nil {
  223. return errResponse, errors.New(err.Error())
  224. }
  225. err = database.Update(dbExecutor, &sql.UpdateExecuteParams{
  226. TableName: userTableName,
  227. TableRow: sql.NewTableRow().Add(user.ColumnToken, token).
  228. Add(user.FieldLastLoginTime, time.Now()),
  229. Conditions: sql.NewConditions().Equal(entity.ColumnID, existUser.ID),
  230. })
  231. if err != nil {
  232. return errResponse, errors.New(err.Error())
  233. }
  234. return map[string]any{
  235. "token": token,
  236. }, nil
  237. },
  238. })
  239. // 注销
  240. binding.PostBind(binder, &binding.SimpleBindItem[any]{
  241. Path: "/logout",
  242. SendResponseFunc: response.SendMsgResponse,
  243. ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
  244. userInfo := c.GetUserInfo()
  245. userTableName := domain.TableName(simple.Schema, &user.Entity{})
  246. dbExecutor := i.DBExecutor()
  247. err := database.Update(dbExecutor, &sql.UpdateExecuteParams{
  248. TableName: userTableName,
  249. TableRow: sql.NewTableRow().Add(user.ColumnToken, ""),
  250. Conditions: sql.NewConditions().Equal(entity.ColumnID, userInfo.GetID()),
  251. })
  252. if err != nil {
  253. return nil, errors.New(err.Error())
  254. }
  255. return nil, nil
  256. },
  257. }, simple.AuthMiddleware)
  258. // Challenge
  259. binding.PostBind(binder, &binding.SimpleBindItem[UserWithRoleInfo]{
  260. Path: "/challenge",
  261. SendResponseFunc: response.SendInfoResponse[UserWithRoleInfo],
  262. ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (UserWithRoleInfo, error) {
  263. errInfo := UserWithRoleInfo{
  264. RoleInfos: make([]role.Info, 0),
  265. }
  266. userInfo := c.GetUserInfo()
  267. userAndRoleTableName := domain.RelationTableName(simple.Schema, &user.Entity{}, &role.Entity{})
  268. roleTableName := domain.TableName(simple.Schema, &role.Entity{})
  269. dbExecutor := i.DBExecutor()
  270. roleIDResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
  271. TableName: userAndRoleTableName,
  272. SelectColumns: []string{domain.RelationColumnName(&role.Entity{})},
  273. Conditions: sql.NewConditions().Equal(domain.RelationColumnName(&user.Entity{}), userInfo.GetID()),
  274. PageNo: 0,
  275. PageSize: 0,
  276. })
  277. if err != nil {
  278. return errInfo, errors.New(err.Error())
  279. }
  280. if totalCount == 0 {
  281. return UserWithRoleInfo{
  282. UserInfo: *(userInfo.(*user.Info)),
  283. RoleInfos: make([]role.Info, 0),
  284. }, nil
  285. }
  286. roleIDs := make([]string, len(roleIDResults))
  287. for index, roleIDResult := range roleIDResults {
  288. roleIDs[index] = roleIDResult.ColumnValueString(domain.RelationColumnName(&role.Entity{}))
  289. }
  290. roleResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
  291. TableName: roleTableName,
  292. Conditions: sql.NewConditions().In(entity.ColumnID, roleIDs),
  293. PageNo: 0,
  294. PageSize: 0,
  295. })
  296. if err != nil {
  297. return errInfo, errors.New(err.Error())
  298. }
  299. if totalCount == 0 {
  300. return UserWithRoleInfo{
  301. UserInfo: *(userInfo.(*user.Info)),
  302. RoleInfos: make([]role.Info, 0),
  303. }, nil
  304. }
  305. roleInfos := make([]role.Info, 0)
  306. err = sql.ParseSqlResult(roleResults, &roleInfos)
  307. if err != nil {
  308. return errInfo, errors.New(err.Error())
  309. }
  310. return UserWithRoleInfo{
  311. UserInfo: *(userInfo.(*user.Info)),
  312. RoleInfos: roleInfos,
  313. }, nil
  314. },
  315. }, simple.AuthMiddleware)
  316. }
  317. func BindAuth(app *application.App, simple *Simple) {
  318. binder := binding.NewBinder(app.ChooseRouter(api.RouterPrefix, ""), app.Infrastructure())
  319. simple.init(app.Infrastructure())
  320. simple.bind(binder)
  321. }