Skip to content

认证授权

底座管理系统实现了登录认证及后端接口的权限控制等功能。支持轻量级FilterSpringSecurity两种模式。具体组件坐标如下:

xml
<!-- 认证及授权相关controller接口及web配置 -->
<dependency>
    <groupId>cn.zjtele.pubinfo.sys.auth</groupId>
    <artifactId>auth-api</artifactId>
</dependency>

<!-- 认证及授权相关服务及扩展定义 -->
<dependency>
    <groupId>cn.zjtele.pubinfo.sys.auth</groupId>
    <artifactId>auth-core</artifactId>
</dependency>

<!-- 基于底座rbac的相关服务扩展实现 -->
<dependency>
    <groupId>cn.zjtele.pubinfo.sys.auth</groupId>
    <artifactId>auth-rbac</artifactId>
</dependency>

认证鉴权流程

认证鉴权鉴权模式

底座管理系统支持支持轻量级FilterSpringSecurity两种认证鉴权模式。

轻量级Filter模式

默认情况,系统使用轻量级Filter模式,认证过滤器cn.zjtele.pubinfo.sys.auth.filter.AuthenticationFilter及鉴权过滤器cn.zjtele.pubinfo.sys.auth.filter.AuthorizationFilter进行登录认证及后端接口权限校验。

SpringSecurity模式

如果引入了SpringSecurity的maven依赖,自动切换为SpringSecurity模式。

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

接口鉴权逻辑

如果需要针对某个后端接口进行权限校验,需要在资源管理页面,对资源进行编辑,配置资源对应的权限标识,权限标识为后端接口地址(不包含contextPath),多个以逗号分隔。这样如果用户拥有该资源的权限,则拥有该后端接口的访问权限。没有在资源中配置的其他接口,则不进行接口权限校验。具体页面配置如下:

配置介绍

登录认证、授权校验,密码等相关配置

yaml
pubinfo:
  # 认证授权相关配置
  auth:
    # 登录后访问token相关配置
    access-token:
      # 访问token的过期时间
      expire-time: 1800000
      # 访问token的生成签名key
      key: UT@33oUY*
    # 登录后刷新token相关配置
    refresh-token:
      # 刷新token的生成签名key
      key: OK@213YU#
      # 刷新token的过期时间
      expire-time: 36000000
    # 登录认证相关配置
    authentication:
      # 登录认证开关
      enable: true
      # 登录认证白名单url列表
      white-path: /test/**
    # 登录授权相关配置
    authorization:
      # 登录授权校验开关
      enable: true
      # 接口授权校验白名单,白名单内接口所有用户都可访问
      white-path: /auth/changeLoginOrg,/dict/item/list,/rbac/user/userEntireInfo,/rbac/resource/grantedResources,/rbac/user/changePassword
    # 登录锁定配置
    login-lock:
      # 登录锁定开关
      enable: true
      # 允许失败次数
      allow-fail-counts: 5
      # 锁定时间,单位分钟
      lock-minutes: 5
    # 验证码开关
    valid-code-enable: true
    rsa:
      # 登录密码传输公钥
      public-key: xxx
      # 登录密码传输私钥
      private-key: xxx

默认密码、密码有效期及密码校验规则配置

yaml
pubinfo:
  rbac:
    password:
      # 默认密码
      default-password: xxxxxx
      # 密码有效期
      expire-days: 180
      # 是否强制修改初始密码
      force-change-init-pwd: true
      # 密码不能重复次数
      num-of-recent-no-repeat: 2
      # 密码校验器
      strength-checker-list: contentRegex,length,keyBoard,oldPassword,userName

由于密码传输的加解密相关代码在auth-core组件中,如果其他业务模块中也有需要加密传输密码的需要,同时为了避免模块间的依赖,可以通过切面方式统一解密密码,具体配置如下

yaml
pubinfo:
  rsa-decrypt:
    # 密码解密切点列表
    point-cuts:
      # 切点表达式
      - expression: execution (* cn.zjtele.pubinfo.sys.rbac.core.service.PubPwdChangeLogService.changePassword(..))
        # 需要解密的参数列表,值为springel表达式
        param:
          - '#root[0]'
          - '#root[1]'

登录方式扩展

目前底座只有用户名密码登录方式,但是支持自行扩展新的登录方式,具体扩展步骤如下:

  • 1、继承cn.zjtele.pubinfo.sys.auth.spi.domain.BaseLoginReq(包含登录方式loginType),定义对应的登录请求参数。
  • 2、实现cn.zjtele.pubinfo.sys.auth.spi.IdentityAuthenticator接口,完成具体的登录认证逻辑,返回用户信息。其中该接口返回的loginType为登录时传入的参数。
  • 3、定义新的登录controller接口,入参为步骤1中定义的参数。
  • 4、配置文档,可以在认证服务分组下,packages-to-scan加上对应的包路径。

相关实例代码如下:

请求参数实现示例

java
@Schema(name = "QrCodeLoginReq", description = "扫码登录请求对象")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper=true)
public class QrCodeLoginReq extends BaseLoginReq {
    @Schema(description = "二维码", requiredMode = Schema.RequiredMode.REQUIRED)
    private String qrCode;
}

认证器实现示例:

java
@Component
public class QrCodeLoginIdentityAuthenticator implements IdentityAuthenticator {
    @Override
    public UserAccount verify(BaseLoginReq req) {
        QrCodeLoginReq loginReq = (QrCodeLoginReq)req;

        String userId = getUserIdByCode(loginReq.getQrCode());
        if(userId == null) {
            throw new BizLogicException("扫码登录异常,用户不存在");
        }

        UserAccount userAccount = getUserAccountByUserId(userId);
        return userAccount;
    }

    /**
     * 根据code获取登录用户信息
     * @param code
     * @return
     */
    private String getUserIdByCode(String code) {
        //todo 调用第三方接口获取
        return null;
    }

    private UserAccount getUserAccountByUserId(String userId) {
        //todo 调用第三方接口获取
        return null;
    }

    @Override
    public String getType() {
        return "qrCode";
    }
}

controller接口代码示例:

java
@Tag(name = "认证服务")
@RestController
@RequestMapping(AuthConstant.BASE_MAPPING + "/")
public class ExtendLoginController {
    @Resource
    private LoginService loginService;

    @OperationLog(operateType = LogOperatorType.LOGIN)
    @Operation(summary = "扫码登录")
    @PostMapping("/loginByQrCode")
    public ResponseData<LoginTokenVo> loginByQrCode(@RequestBody QrCodeLoginReq req) {
        LoginTokenVo loginTokenResp = loginService.login(req);
        if (loginTokenResp.getLoginResponse() != null) {
            return ResponseData.build(loginTokenResp.getLoginResponse(), loginTokenResp);
        }
        return ResponseData.success(loginTokenResp);
    }
}