auth.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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(urlPrefix string, 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([]permission_group.Entity, 0)
  105. permissionEntities := make([]permission.Entity, 0)
  106. permissionIDs := make([]string, 0)
  107. permissionInGroup := make(map[string][]string)
  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: urlPrefix + perm[1],
  118. Action: perm[2],
  119. UserIDFields: entity.UserIDFields{
  120. CreateUserID: adminUserID,
  121. LastUpdateUserID: adminUserID,
  122. },
  123. })
  124. }
  125. permissionIDs = append(permissionIDs, permissionInGroupIDs...)
  126. permissionGroupID := strutils.SimpleUUID()
  127. permissionInGroup[permissionGroupID] = permissionInGroupIDs
  128. permissionGroupEntities = append(permissionGroupEntities, permission_group.Entity{
  129. Base: entity.Base{ID: permissionGroupID},
  130. Name: permissionGroupName,
  131. Description: permissionGroupName,
  132. UserIDFields: entity.UserIDFields{
  133. CreateUserID: adminUserID,
  134. LastUpdateUserID: adminUserID,
  135. },
  136. })
  137. }
  138. encryptedAdminUserPassword, err := encoding.AESEncrypt(simple.AdminUserPassword, simple.AESKey)
  139. if err != nil {
  140. panic(err)
  141. }
  142. adminUserEntity := &user.Entity{
  143. Base: entity.Base{ID: adminUserID},
  144. UserName: adminUserName,
  145. Password: encryptedAdminUserPassword,
  146. Name: adminUserName,
  147. }
  148. adminRoleEntity := &role.Entity{
  149. Base: entity.Base{ID: adminRoleID},
  150. Name: adminRoleName,
  151. Description: adminRoleName,
  152. UserIDs: []string{adminUserID},
  153. UserIDFields: entity.UserIDFields{
  154. CreateUserID: adminUserID,
  155. LastUpdateUserID: adminUserID,
  156. },
  157. }
  158. err = database.Transaction(dbExecutor, func(tx database.Executor) error {
  159. // 创建权限
  160. err := database.InsertEntity(tx, domain.TableName(simple.Schema, &permission.Entity{}), permissionEntities)
  161. if err != nil {
  162. return err
  163. }
  164. // 创建权限组
  165. err = database.InsertEntity(tx, domain.TableName(simple.Schema, &permission_group.Entity{}), permissionGroupEntities)
  166. if err != nil {
  167. return err
  168. }
  169. // 创建管理员角色
  170. err = database.InsertEntity(tx, domain.TableName(simple.Schema, &role.Entity{}), adminRoleEntity)
  171. if err != nil {
  172. return err
  173. }
  174. // 创建管理员用户
  175. err = database.InsertEntity(tx, domain.TableName(simple.Schema, &user.Entity{}), adminUserEntity)
  176. if err != nil {
  177. return err
  178. }
  179. // 关联权限组和权限
  180. permissionGroupAndPermissionTableRows := make([]sql.TableRow, 0)
  181. for permissionGroupID, permissionInGroupIDs := range permissionInGroup {
  182. for _, permissionInGroupID := range permissionInGroupIDs {
  183. tableRow := sql.NewTableRow().
  184. Add(domain.RelationColumnName(&permission_group.Entity{}), permissionGroupID).
  185. Add(domain.RelationColumnName(&permission.Entity{}), permissionInGroupID)
  186. permissionGroupAndPermissionTableRows = append(permissionGroupAndPermissionTableRows, *tableRow)
  187. }
  188. }
  189. err = database.InsertBatch(tx, &sql.InsertBatchExecuteParams{
  190. TableName: domain.RelationTableName(simple.Schema, &permission_group.Entity{}, &permission.Entity{}),
  191. TableRowBatch: permissionGroupAndPermissionTableRows,
  192. })
  193. if err != nil {
  194. return err
  195. }
  196. // 关联管理员角色和权限
  197. roleAndPermissionTableRows := make([]sql.TableRow, 0)
  198. for _, permissionID := range permissionIDs {
  199. tableRow := sql.NewTableRow().
  200. Add(domain.RelationColumnName(&role.Entity{}), adminRoleID).
  201. Add(domain.RelationColumnName(&permission.Entity{}), permissionID)
  202. roleAndPermissionTableRows = append(roleAndPermissionTableRows, *tableRow)
  203. }
  204. err = database.InsertBatch(tx, &sql.InsertBatchExecuteParams{
  205. TableName: domain.RelationTableName(simple.Schema, &role.Entity{}, &permission.Entity{}),
  206. TableRowBatch: roleAndPermissionTableRows,
  207. })
  208. if err != nil {
  209. return err
  210. }
  211. // 关联管理员用户和管理员角色
  212. err = database.Insert(tx, &sql.InsertExecuteParams{
  213. TableName: domain.RelationTableName(simple.Schema, &user.Entity{}, &role.Entity{}),
  214. TableRow: sql.NewTableRow().
  215. Add(domain.RelationColumnName(&user.Entity{}), adminUserID).
  216. Add(domain.RelationColumnName(&role.Entity{}), adminRoleID),
  217. })
  218. if err != nil {
  219. return err
  220. }
  221. return nil
  222. })
  223. if err != nil {
  224. panic(err)
  225. }
  226. }
  227. func (simple *Simple) bind(binder *binding.Binder) {
  228. (&permission.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  229. (&permission_group.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  230. (&role.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  231. (&user.Simple{Schema: simple.Schema, AESKey: simple.AESKey, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  232. (&relations.Simple{Schema: simple.Schema, AuthMiddleware: simple.AuthMiddleware}).Bind(binder)
  233. // 登录
  234. binding.PostBind(binder, &binding.SimpleBindItem[map[string]any]{
  235. Path: "/login",
  236. SendResponseFunc: response.SendMapResponse,
  237. RequestParams: &LoginJsonBody{},
  238. ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (map[string]any, error) {
  239. errResponse := map[string]any{
  240. "token": "",
  241. }
  242. jsonBody, err := request.ToConcrete[*LoginJsonBody](params)
  243. if err != nil {
  244. return errResponse, err
  245. }
  246. encryptedPassword, err := encoding.AESEncrypt(jsonBody.Password, simple.AESKey)
  247. if err != nil {
  248. return errResponse, errors.New(err.Error())
  249. }
  250. userTableName := domain.TableName(simple.Schema, &user.Entity{})
  251. dbExecutor := i.DBExecutor()
  252. result, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{
  253. TableName: userTableName,
  254. Conditions: sql.NewConditions().
  255. Equal(user.ColumnUserName, jsonBody.UserName).
  256. Equal(user.ColumnPassword, encryptedPassword),
  257. })
  258. if err != nil {
  259. if database.IsErrorDBRecordNotExist(err) {
  260. return errResponse, errors.New("用户名或密码错误")
  261. }
  262. return errResponse, errors.New(err.Error())
  263. }
  264. existUser := new(user.Entity)
  265. err = sql.ParseSqlResult(result, existUser)
  266. if err != nil {
  267. return errResponse, err
  268. }
  269. token, err := jwt_tools.NewJWT(simple.JWTSecretKey, existUser.ID, simple.JWTExpiredSec)
  270. if err != nil {
  271. return errResponse, errors.New(err.Error())
  272. }
  273. err = database.Update(dbExecutor, &sql.UpdateExecuteParams{
  274. TableName: userTableName,
  275. TableRow: sql.NewTableRow().Add(user.ColumnToken, token).
  276. Add(user.ColumnLastLoginTime, time.Now().Local()),
  277. Conditions: sql.NewConditions().Equal(entity.ColumnID, existUser.ID),
  278. })
  279. if err != nil {
  280. return errResponse, errors.New(err.Error())
  281. }
  282. return map[string]any{
  283. "token": token,
  284. }, nil
  285. },
  286. })
  287. // 注销
  288. binding.PostBind(binder, &binding.SimpleBindItem[any]{
  289. Path: "/logout",
  290. SendResponseFunc: response.SendMsgResponse,
  291. ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
  292. userInfo := c.GetUserInfo()
  293. userTableName := domain.TableName(simple.Schema, &user.Entity{})
  294. dbExecutor := i.DBExecutor()
  295. err := database.Update(dbExecutor, &sql.UpdateExecuteParams{
  296. TableName: userTableName,
  297. TableRow: sql.NewTableRow().Add(user.ColumnToken, ""),
  298. Conditions: sql.NewConditions().Equal(entity.ColumnID, userInfo.GetID()),
  299. })
  300. if err != nil {
  301. return nil, errors.New(err.Error())
  302. }
  303. return nil, nil
  304. },
  305. }, simple.AuthMiddleware)
  306. // Challenge
  307. binding.PostBind(binder, &binding.SimpleBindItem[UserWithRoleInfo]{
  308. Path: "/challenge",
  309. SendResponseFunc: response.SendInfoResponse[UserWithRoleInfo],
  310. ServiceFunc: func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (UserWithRoleInfo, error) {
  311. errInfo := UserWithRoleInfo{
  312. RoleInfos: make([]role.Info, 0),
  313. }
  314. userInfo := c.GetUserInfo()
  315. userAndRoleTableName := domain.RelationTableName(simple.Schema, &user.Entity{}, &role.Entity{})
  316. roleTableName := domain.TableName(simple.Schema, &role.Entity{})
  317. dbExecutor := i.DBExecutor()
  318. roleIDResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
  319. TableName: userAndRoleTableName,
  320. SelectClauses: []string{domain.RelationColumnName(&role.Entity{})},
  321. Conditions: sql.NewConditions().Equal(domain.RelationColumnName(&user.Entity{}), userInfo.GetID()),
  322. PageNo: 0,
  323. PageSize: 0,
  324. })
  325. if err != nil {
  326. return errInfo, errors.New(err.Error())
  327. }
  328. if totalCount == 0 {
  329. return UserWithRoleInfo{
  330. UserInfo: *(userInfo.(*user.Info)),
  331. RoleInfos: make([]role.Info, 0),
  332. }, nil
  333. }
  334. roleIDs := make([]string, 0)
  335. err = sql.ParseSqlResult(roleIDResults, &roleIDs)
  336. if err != nil {
  337. return errInfo, errors.New(err.Error())
  338. }
  339. roleResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
  340. TableName: roleTableName,
  341. Conditions: sql.NewConditions().In(entity.ColumnID, roleIDs),
  342. PageNo: 0,
  343. PageSize: 0,
  344. })
  345. if err != nil {
  346. return errInfo, errors.New(err.Error())
  347. }
  348. if totalCount == 0 {
  349. return UserWithRoleInfo{
  350. UserInfo: *(userInfo.(*user.Info)),
  351. RoleInfos: make([]role.Info, 0),
  352. }, nil
  353. }
  354. roleInfos := make([]role.Info, 0)
  355. err = sql.ParseSqlResult(roleResults, &roleInfos)
  356. if err != nil {
  357. return errInfo, errors.New(err.Error())
  358. }
  359. return UserWithRoleInfo{
  360. UserInfo: *(userInfo.(*user.Info)),
  361. RoleInfos: roleInfos,
  362. }, nil
  363. },
  364. }, simple.AuthMiddleware)
  365. }
  366. func BindAuth(app *application.App, simple *Simple) {
  367. prefixRootRouter := app.ChooseRouter(api.RouterPrefix, "")
  368. binder := binding.NewBinder(prefixRootRouter, app.Infrastructure())
  369. simple.init(prefixRootRouter.BasePath(), app.Infrastructure())
  370. simple.bind(binder)
  371. }