POST /auth/oauth2/token?grant_type=password&scope=server HTTP/1.1
Host: pig-gateway:9999
Authorization: Basic dGVzdDp0ZXN0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32
username=admin&password=YehdBPev

网关前置处理

网关中最重要的功能是路由转发,根据请求前缀匹配到对应服务。比如所有以 /auth 开头的请求会自动转发至 pig-auth 服务的接口处理。

spring:
  cloud:
    gateway:
      routes:
        # 认证中心
        - id: pig-auth
          uri: lb://pig-auth
          predicates:
            - Path=/auth/**
        #UPMS 模块
         ...

PigRequestGlobalFilter 过滤器中另外一个重要的功能就是截取路由前缀

例如:http://127.0.0.1:9999/auth/oauth2/token 转发到 pig-auth 的请求路径自动截取 前缀变成http://127.0.0.1:3000/oauth2/token

验证码校验处理

pig-auth 认证中心在接收到网关转发的请求后,会通过 ValidateCodeFilter 对验证码(图形、短信)等进行校验

前端请求密文解密

pig-auth 在处理完验证码判断逻辑后,PasswordDecoderFilter 针对 /oauth2/token 请求会进行前端密码解密。

password密文:JFat0Zdc

转成

password明文:123456

客户端认证处理

如上图在登录请求中会携带 Basic base64(clientId:clientSecret),那么首先OAuth2ClientAuthenticationFilter 会通过调用 RegisteredClientRepository (数据库存储) 来判断传入的客户端是否正确

正式接收登录请求

OAuth2TokenEndpointFilter 会接收通过上文 OAuth2ClientAuthenticationFilter 客户端认证的请求

组装认证对象

AuthenticationConverter 会根据请求中的参数和授权类型组装成对应的授权认证对象

登录认证对象

public class XXXAuthenticationToken extends OAuth2ResourceOwnerBaseAuthenticationToken {

}

授权认证调用

核心认证逻辑

多用户体系匹配 UserDetailsService

密码匹配校验

用户状态校验

用户查询逻辑

用户查询逻辑的多种实现形式

  • **解耦:通过 feign 查询其他系统获取并组装成 **UserDetails
  • 简单:认证中心直接查询 DB **并组装成 **UserDetails

密码校验逻辑

默认支持加密方式如下:

密码明文

密码密文

PasswordEncoder 会自动根据特征码匹配对应的加密算法,所以上一步⑧ 查询用户对象组装成 UserDetails 需要特殊处理

return new UserDetails(user.getUsername(),"{bcrypt}"+"数据库存储的密文");

生成 OAuth2AccessToken

Token 存储持久化

当前 SAS 仅支持 JDBC 和内存,PIG 扩展支持 Redis 实现

登录成功事件处理

基于 SpringEvent 事件处理,可以在这里做更多的处理 日志、个性化等处理逻辑

请求结果输出 Token

private void sendAccessTokenResponse(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication) throws IOException {

    OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) authentication;

    OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
    OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
    Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
    // 无状态 注意删除 context 上下文的信息
    SecurityContextHolder.clearContext();
    this.accessTokenHttpResponseConverter.write(accessTokenResponse, null, httpResponse);
}

定义具体的输出返回格式等逻辑

♥️ 获取支持

遇到问题?

如果您在使用过程中遇到任何问题、有功能建议或需求,请点击此卡片前往 Gitee 仓库提交 Issue。