• HZERO微服务平台07: 代码分析之登录日志、验证码登录、jwt token等


    登陆日志

    分析

    LoginAuditProcessor记录登陆日志, 只能记录隐式流程、手机号跳转;
    新增了AuthenticationSuccessEventListener, 用来记录password流程;
    2021-04-02: client_credentials还不能记录
    授权码模式未测试;

    代码流程

    从下向上找的分析过程:

    表: hpfm_audit_login
    实体: AuditLogin
    记录日志都要调用Repository, 全局搜索: auditLoginRepository.  
    AuditLoginServiceImpl#login
    AuditLoginServiceImpl#addLoginRecord
    LoginAuditProcessor#process
    两个位置: 
    1. AuthorizationEndpoint#getImplicitGrantResponse
    
    2. LoginTokenService#createAccessToken
    LoginTokenService#loginForToken
    - UserLoginServiceImpl#loginMobileForToken
    - UserLoginServiceImpl#loginOpenForToken
    

    手机验证码登陆

    地址: /login/sms

    SmsAuthenticationFilter#attemptAuthentication
    ProviderManager#authenticate
    SmsAuthenticationProvider#authenticate
    SmsAuthenticationProvider#additionalAuthenticationChecks
    CaptchaMessageHelper#checkCaptcha
    CaptchaMessageHelper#checkCaptchaWithNumber
    

    redis db3, 数据:

    hoth:captcha:user_type_p:default:code:2649ccbfb2c045c2907790b82107e172
    

    可以不检查验证码:

    //测试时禁用验证功能,不验证验证码是否正确
    //hzero.captcha.testDisable
    
    CaptchaMessageHelper#checkCaptchaWithNumber
    captchaProperties.isTestDisable()
    

    手机验证码获取token

    调用方法

    手机短信登陆 - OAuth Token API

    {{gateway}}/oauth/token/mobile?grant_type=implicit&client_id=localhost&client_secret=secret&phone=18009908012&source_type=app&device_id=123456789&captcha=150217&captchaKey=56a7ef80d1f64834a7ab664daa248f38
    

    代码流程

    LoginController#loginMobileToken
    UserLoginServiceImpl#loginMobileForToken
    LoginTokenService#loginForToken
    // 封装请求参数
    Authentication authRequest = attemptAuthentication(request);
    MobileLoginTokenService#attemptAuthentication
    SmsAuthenticationToken authRequest = new SmsAuthenticationToken(mobile); //mobile是手机号
    authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); //验证码、key等参数在detail里
    Authentication authentication = authenticationProvider.authenticate(authRequest);
    SmsAuthenticationProvider#authenticate
    SmsAuthenticationProvider#additionalAuthenticationChecks
    CaptchaResult captchaResult = captchaMessageHelper.checkCaptcha(captchaKey, inputCaptcha, mobile, getUserType(authentication),businessScope, IospService.Oauth.CODE, false);
    CaptchaMessageHelper#checkCaptchaWithNumber  //验证验证码 hzero-starter-redis.jar
    

    jwt token、@EnableChoerodonResourceServer

    @EnableChoerodonResourceServer注解

    作用是: 开启资源认证, 解析jwt token、设置用户信息;

    实现方式:
    这个注解的作用就是导入配置类:
    @Import({ChoerodonResourceServerConfiguration.class})

    配置类继承自spring security的配置adapter:

    public class ChoerodonResourceServerConfiguration extends WebSecurityConfigurerAdapter {
    ...
    

    配置类里配置了HttpSecurity, 注册了JwtTokenFilterJwtTokenExtractortokenStoretokenServices

    JwtTokenFilter 过滤器

    @EnableChoerodonResourceServer的一个重要功能是添加了JwtTokenFilter过滤器;
    JwtTokenFilter的作用是解析jwt_token header, 设置用户信息到SecurityContextHolder;
    JwtTokenFilter的作用路径默认是/v1/*, 可以如下配置:

    hzero:
      resource:
        # JwtTokenFilter应用的路径; 注意是/*不是/**
        pattern: /v1/*,/api/*
        # JwtTokenFilter跳过的路径; 只能精确匹配
        skip-path: /v2/choerodon/api-docs
        # 如果设置了context-path,需要设置为
        # skip-path: ${server.servlet.context-path}/v2/choerodon/api-docs
    

    pattern的格式是servlet的filter的格式, /v1/*/user无效的, 详见:
    我的笔记: spring web/mvc topic .md

    jwt token的密钥

    设置密钥:

    ChoerodonResourceServerConfiguration#accessTokenConverter
    converter.setSigningKey(properties.getOauthJwtKey());  //默认是hzero
    

    这个拦截器可以生成token:
    (restTemplate、feignClient的请求会自动添加jwt_token header)

    ...core.net.RequestHeaderCopyInterceptor#intercept
    token = OAUTH_TOKEN_PREFIX + JwtHelper.encode(objectMapper.writeValueAsString(details.getDecodedDetails()), signer).getEncoded();
    

    默认使用HMACSHA256(HS256)算法, 是对称加密, 把key写到了配置文件hzero.oauthJwtKeyCoreProperties#oauthJwtKey;

    HS256 使用同一个「secret_key」进行签名与验证(对称加密)。一旦 secret_key 泄漏,就毫无安全性可言了。

    • 因此 HS256 只适合集中式认证,签名和验证都必须由可信方进行。
    • 传统的单体应用广泛使用这种算法,但是请不要在任何分布式的架构中使用它!

    JWT 签名算法 HS256、RS256 及 ES256 及密钥生成 - 於清樂 - 博客园

    自定义client secret错误时的返回方式

    client secret错误时会返回302, 重定向到登录页, 希望改造为返回401, 提示json格式的错误信息;
    解决方式: 覆写hzero-oauth定义的SsoAuthenticationEntryPoint

    调用过程:

    BasicAuthenticationFilter  //校验client secret, 校验失败
    this.authenticationEntryPoint.commence(request, response, failed);
    BasicAuthenticationEntryPoint#commence  //设置401
    ExceptionTranslationFilter#doFilter //捕获filter的异常
    ExceptionTranslationFilter#handleSpringSecurityException
    ExceptionTranslationFilter#sendStartAuthentication
    authenticationEntryPoint.commence(request, response, reason);
    SsoAuthenticationEntryPoint#commence
    response.sendRedirect(redirectUrl);
    
  • 相关阅读:
    团队冲刺第二天
    电梯演讲的准备——冰淇淋第一个项目NABCD分析
    团队冲刺第四天
    团队冲刺第六天
    团队冲刺第三天
    团队冲刺第一天
    XmlDocument类的WriteContentTo和WriteTo方法
    从一场DOTA对战中发现的哲理,也做为对2012年的展望
    String.Trim()真相大揭秘
    SQL Server 2008数据库维护计划
  • 原文地址:https://www.cnblogs.com/QIAOXINGXING001/p/15594752.html
Copyright © 2020-2023  润新知