五、接口使用说明 - ZeroOrInfinity/UMS GitHub Wiki

  1. user service: Must implemente

  2. RBAC-based access control: Support multi-tenancy

    • UriAuthorizeService: 推荐通过实现 AbstractUriAuthorizeService 来实现此接口

    • AbstractUriAuthorizeService: 必须实现(Must implemente)

      • uri(资源) 访问权限控制服务接口抽象类, 定义了基于(角色/多租户/SCOPE)的访问权限控制逻辑. 实现 AbstractUriAuthorizeService 抽象类并注入 IOC 容器即可替换 DefaultUriAuthorizeService.

      • 注意:

        1. 推荐实现 AbstractUriAuthorizeService 同时实现 UpdateCacheOfRolesResourcesService 更新与缓存权限服务, 有助于提高授权服务性能.

        2. 对传入的 Authentication 的 authorities 硬性要求:

         // 此 authorities 可以包含:  [ROLE_A, ROLE_B, ROLE_xxx TENANT_110110, SCOPE_read, SCOPE_write, SCOPE_xxx]
         // authorities 要求:
         //    1. 角色数量    >= 0
         //    2. SCOPE 数量 >= 0
         //    3. 多租户数量  1 或 0
         //    4. 角色数量 + SCOPE 数量  >= 1
         Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        

        3. 此框架默认实现 hasPermission(Authentication, HttpServletRequest) 方法访问权限控制, 通过 UriAuthoritiesPermissionEvaluator 实现, 使用此接口的前提条件是: 应用使用的是 restful 风格的 API; 如果不是 restful 风格的 API, 请使用 hasPermission(Authentication, String, String) 接口的访问权限控制, 此接口使用注解的方式 @PerAuthorize("hasPermission('/users', 'list')") 来实现, 使用注解需先开启 @EnableGlobalMethodSecurity(prePostEnabled = true) 注解.

    • UpdateCacheOfRolesResourcesService:

      • 用于更新并缓存基于(角色/多租户/SCOPE)角色的权限的服务接口, 每次更新角色的 uri(资源)权限时,需要调用此接口, 推荐实现此 RolePermissionsService 接口, 会自动通过 AOP 方式实现发布 UpdateRolesResourcesEvent 事件, 从而调用 UpdateCacheOfRolesResourcesService 对应的方法.

      • 建议:

        1. 基于 角色 的权限控制: 实现所有角色 uri(资源) 的权限 Map(roleAuthority, map(uri, Set(permission))) 的更新与缓存本机内存.

        2. 基于 SCOPE 的权限控制: 情况复杂一点, 但 SCOPE 类型比较少, 也还可以像 1 的方式实现缓存本机内存与更新.

        3. 基于 多租户 的权限控制: 情况比较复杂, 租户很少的情况下, 也还可以全部缓存在本机内存, 通常情况下全部缓存内存不现实, 只能借助于类似 redis 等的内存缓存.

    • RolePermissionsService:

      • 更新与查询基于(角色/多租户/SCOPE)的角色资源服务接口. 主要用于给角色添加权限的操作.

      • 注意:

        1. 在添加资源时, 通过PermissionType.getPermission() 来规范的权限格式, 因为要支持 restful 风格的 Api, 在授权时需要对 HttpMethod 与对应的权限进行匹配判断

        2. 如果实现了 UpdateCacheOfRolesResourcesService 接口, 未实现 RolePermissionsService 接口, 修改或添加基于"角色/多租户/SCOPE "的资源权限时一定要调用 UpdateCacheOfRolesResourcesService 对应的方法, 有两种方式: 一种发布事件, 另一种是直接调用对应服务;

        // 1. 推荐用发布事件(异步执行)
        applicationContext.publishEvent(new UpdateRolesResourcesEvent(true, UpdateRoleResourcesDto);
        // 2. 直接调用服务
        // 角色权限资源
        UpdateCacheOfRolesResourcesService.updateAuthoritiesByRoleId(roleId, resourceClass, resourceIds);
        // 多租户的角色权限资源
        UpdateCacheOfRolesResourcesService.updateAuthoritiesByRoleIdOfTenant(tenantId, roleId, resourceClass, resourceIds);
        // SCOPE 的角色权限资源
        UpdateCacheOfRolesResourcesService.updateAuthoritiesByScopeId(scopeId, roleId, resourceClass, resourceIds);
        // 角色组权限资源
        UpdateCacheOfRolesResourcesService.updateRolesByGroupId(groupId, roleIds);
        // 多租户的角色组权限资源
        UpdateCacheOfRolesResourcesService.updateRolesByGroupIdOfTenant(tenantId, groupId, roleIds);
        

        3. 实现此 RolePermissionsService 接口, 不需要执行上两种方法的操作, 已通过 AOP 方式实现发布 UpdateRolesResourcesEvent 事件.

        4. 注意: RolePermissionsServiceAspect 切面生效前提, 事务的 Order 的值必须 大于 1, 如果是默认事务(优先级为 Integer.MAX_VALUE )不必关心这个值, 如果是自定义事务, 且设置了 Order 的值, 那么值必须 大于 1.

    • 时序图

时序图

- 权限更新及权限缓存实时更新时序图

权限更新及权限缓存实时更新时序图

  1. 验证码(ValidateCode)
  • 短信验证码(SMS validate code): 默认空实现

  • 图片验证码(image validate code): 已实现缓存功能, 支持定时刷新缓存功能, 可以自定义缓存验证码图片的输出路径与缓存数量

  • 滑块验证码(Slider validate code): 已实现缓存功能, 支持定时刷新缓存功能, 可以自定义缓存验证码图片的输出路径与缓存数量, 支持自定义源图片路径与模板图片路径(源图片与模板图片参考 validate-code-example)

  • 自定义验证码(customize validate code):

  1. OAuth2
  • 对 OAuth2 流程中的 state 进行自定义编解码. 可以传递必要的信息

    • Auth2StateCoder: 用户需要时实现, 对第三方授权登录流程中的 state 进行自定义编解码. 可以传递必要的信息, 如: 第三方登录成功的跳转地址等 注意此接口的两个方法必须同时实现对应的编解码逻辑, 实现此接口后注入 IOC 容器即可, 如有前端向后端获取 authorizeUrl 时向后端传递额外参数 且用作注册时的信息, 需配合 UmsUserDetailsService.registerUser(AuthUser, String, String, String) 方法实现.
  • 获取第三方用户信息的接口

    • Auth2UserService: 获取第三方用户信息的接口, 一般不需要用户实现, 除非想自定义获取第三方用户信息的逻辑, 实现此接口注入 IOC 容器即可替代.
  • 第三方授权登录用户的注册, 绑定, 更新第三方用户信息与 accessToken 信息的接口

    • ConnectionService: 第三方授权登录用户的注册, 绑定, 更新第三方用户信息与 accessToken 信息的接口, 一般不需要用户实现. 除非想自定义获取第三方用户信息的逻辑, 实现此接口注入 IOC 容器即可替代.

      • 注意: 要关闭应用启动时自动创建内置的 auth_tokenuser_connection 表设置属性 ums.repository.enableStartUpInitializeTable = false .

      • UsersConnectionRepository: 第三方授权登录的第三方用户信息增删改查, 绑定与解绑及查询是否绑定与解绑接口, 一般不需要用户实现. 除非想自定义获取第三方用户信息的逻辑, 实现此接口注入 IOC 容器即可替代.

      • UsersConnectionTokenRepository: 第三方授权登录用户 accessToken 信息表增删改查接口, 一般不需要用户实现. 除非想自定义获取第三方用户信息的逻辑, 实现此接口注入 IOC 容器即可替代.

    取消 OAuth2 的内置数据库说明

    一. 同时取消第三方登录的 user_connection 与 auth_token 表

    1. 属性配置

    ums:
      oauth:
        # 是否支持内置的第三方登录用户表(user_connection) 和 auth_token 表. 默认: true.
        # 注意: 如果为 false, 则必须重新实现 ConnectionService 接口.
        enable-user-connection-and-auth-token-table: false
    

    2. 必须重新实现 top.dcenter.ums.security.core.api.oauth.signup.ConnectionService 接口

    二. 取消第三方登录 auth_token 表

    1. 属性配置

    ums:
      oauth:
        # 是否支持内置的第三方登录 token 表(auth_token). 默认: true.
        enable-auth-token-table: false
    
  • 自定义 OAuth2 Login 扩展接口: 内置两个自定义 providerId(ums.oauth.customize 与 ums.oauth.gitlabPrivate)

    • AuthGitlabPrivateSource: 抽象类, 实现此自定义的 AuthGitlabPrivateSource 且注入 ioc 容器的同时, 必须实现 AuthCustomizeRequest , 会自动集成进 OAuth2 Login 逻辑流程中, 只需要像 JustAuth 默认实现的第三方登录一样, 配置相应的属性(ums.oauth.gitlabPrivate.[clientId|clientSecret]等属性)即可.

    • AuthCustomizeSource: 抽象类, 实现此自定义的 AuthCustomizeSource 且注入 ioc 容器的同时, 必须实现 AuthCustomizeRequest , 会自动集成进 OAuth2 Login 逻辑流程中, 只需要像 JustAuth 默认实现的第三方登录一样, 配置相应的属性(ums.oauth.customize.[clientId|clientSecret]等属性)即可.

    • AuthCustomizeRequest: 抽象类, 实现此自定义的 AuthCustomizeRequest 同时, 必须实现 AuthCustomizeSource 或 AuthGitlabPrivateSource 且注入 ioc 容器, 会自动集成进 OAuth2 Login 逻辑流程中, 只需要像 JustAuth 默认实现的第三方登录一样, 配置相应的属性(ums.oauth.customize.[clientId|clientSecret]等属性)即可.

  1. 自定义用户登录成功与失败处理器时, 请继承下面两个抽象类; 方便 ums 自动注入登录功能.

  2. 多租户系统(Multi-tenant)

  • TenantContextHolder:
    • 多租户上下文存储器. 实现此接口并注入 IOC 容器后, 会自动注入 UMS 默认实现的注册/登录/授权组件, 要实现 ums 框架具有多租户功能, 必须实现此接口并注入 IOC 容器.

    • 功能:

      1. tenantIdHandle(HttpServletRequest, String)从注册用户入口或登录用户入口提取 tenantId 及进行必要的逻辑处理(如: tenantId 存入 ThreadLocal , 或存入 session, 或存入 redis 缓存等).

      2. getTenantId()方便后续用户注册、登录、授权的数据处理(如:sql 添加 tenantId 的条件,注册用户添加 TENANT_tenantId 权限,根据 tenantId 获取角色的权限数据).

      3. getTenantId(Authentication) 默认实现方法, 用户已登录的情况下, 获取租户 ID, 直接从 authority 中解析获取.

    • 注意: 1. 多租户系统中, 在未登录时需要用到 tenantId 的接口, 如: UserCache.getUserFromCache(String)/UmsUserDetailsService 等接口, 可通过 getTenantId() 来获取 tenantId. 登录用户可以通过 Authentication 来获取 tenantId.

      2. UMS 默认的登录与注册逻辑中, 都内置了 TenantContextHolder.tenantIdHandle(HttpServletRequest, String) 逻辑, 用户在实现 UserCache/UmsUserDetailsService 等接口中需要 tenantId 时, 调用 TenantContextHolder.getTenantId() 方法即可.

      3. 如果自定义的注册或登录逻辑, 需要自己先调用 TenantContextHolder.tenantIdHandle(HttpServletRequest, String) 逻辑, 再在 实现 UserCache/UmsUserDetailsService 等接口中需要 tenantId 时, 调用 TenantContextHolder.getTenantId() 方法即可.

  1. 任务处理器接口(job)
  • JobHandler
    • 任务处理器接口, 继承此接口并注入 IOC 容器, top.dcenter.ums.security.core.tasks.config.ScheduleAutoConfiguration 会自动注册到 ScheduledTaskRegistrar 中.
  1. JWT 接口请看 jwt-example.

  2. 一键登录(运营商)接口(one-click login)

  • OneClickLoginService: 一键登录必须实现此接口, 根据 accessToken 从服务商获取用户手机号.