Pig4Cloud之检验token

前端校验请求

/src/page/index/index.vue

refreshToken() {
      this.refreshTime = setInterval(() => {
        checkToken(this.refreshLock, this.$store)
      }, 10000)
    }

checkToken

/**
 * 校验令牌,若有效期小于半小时自动续期
 * 
 * 定时任务请求后端接口返回实际的有效时间,不进行本地计算避免 客户端和服务器机器时钟不一致
 * @param refreshLock
 */
export const checkToken = (refreshLock, $store) => {
  const token = store.getters.access_token
  // 获取当前选中的 basic 认证信息
  let basicAuth = getStore({name: 'basicAuth'})

  if(validatenull(token) || validatenull(basicAuth)){
      return;
  }

  request({
    url: '/auth/token/check_token',
    headers: {
      isToken: false,
      Authorization: basicAuth
    },
    method: 'get',
    params: {token}
  }).then(response => {
    const expire = response && response.data && response.data.exp
    if (expire) {
      const expiredPeriod = expire * 1000 - new Date().getTime()
      console.log('当前token过期时间', expiredPeriod, '毫秒')
      //小于半小时自动续约
      if (expiredPeriod <= website.remainingTime) {
        if (!refreshLock) {
          refreshLock = true
          $store.dispatch('RefreshToken')
            .catch(() => {
              clearInterval(this.refreshTime)
            })
          refreshLock = false
        }
      }
    }
  }).catch(error => {
    console.error(error)
  })
}

流程

当用户携带token 请求资源服务器的资源时,Spring Security 拦截token,进行token 和 userdetails 匹配过程,把无状态的token 转化成具体用户

image

BearerTokenAuthenticationFilter

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/server/resource/web/BearerTokenAuthenticationFilter.html
作为一个OncePerRequestFilter核心逻辑在doFilterInternal中。

@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String token;
        try {
            token = this.bearerTokenResolver.resolve(request);
        }
        catch (OAuth2AuthenticationException invalid) {
            this.logger.trace("Sending to authentication entry point since failed to resolve bearer token", invalid);
            this.authenticationEntryPoint.commence(request, response, invalid);
            return;
        }
        if (token == null) {
            this.logger.trace("Did not process request since did not find bearer token");
            filterChain.doFilter(request, response);
            return;
        }

        BearerTokenAuthenticationToken authenticationRequest = new BearerTokenAuthenticationToken(token);
        authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));

        try {
            AuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request);
            Authentication authenticationResult = authenticationManager.authenticate(authenticationRequest);
            SecurityContext context = SecurityContextHolder.createEmptyContext();
            context.setAuthentication(authenticationResult);
            SecurityContextHolder.setContext(context);
            this.securityContextRepository.saveContext(context, request, response);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authenticationResult));
            }
            filterChain.doFilter(request, response);
        }
        catch (AuthenticationException failed) {
            SecurityContextHolder.clearContext();
            this.logger.trace("Failed to process authentication request", failed);
            this.authenticationFailureHandler.onAuthenticationFailure(request, response, failed);
        }
    }

1.拦截请求进行鉴权

BearerTokenAuthenticationFilter 拦截所有资源服务器的请求。
解析 header 或者参数中的 access_token 字段

image

根据access_token 构造出来 BearerTokenAuthenticationToken认证对象

image

请求authenticationManager.authenticate(authenticationRequest);进行鉴权。

image

2.鉴权操作

BearerTokenAuthenticationFilter解析 Authentication: Bearer {token} 中的token,交给 OpaqueTokenAuthenticationProvider

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    if (!(authentication instanceof BearerTokenAuthenticationToken)) {
        return null;
    }
    BearerTokenAuthenticationToken bearer = (BearerTokenAuthenticationToken) authentication;
    OAuth2AuthenticatedPrincipal principal = getOAuth2AuthenticatedPrincipal(bearer);
    AbstractAuthenticationToken result = convert(principal, bearer.getToken());
    result.setDetails(bearer.getDetails());
    this.logger.debug("Authenticated token");
    return result;
}
    
private OAuth2AuthenticatedPrincipal getOAuth2AuthenticatedPrincipal(BearerTokenAuthenticationToken bearer) {
    try {
        return this.introspector.introspect(bearer.getToken());
    }
    catch (BadOpaqueTokenException failed) {
        this.logger.debug("Failed to authenticate since token was invalid");
        throw new InvalidBearerTokenException(failed.getMessage(), failed);
    }
    catch (OAuth2IntrospectionException failed) {
        throw new AuthenticationServiceException(failed.getMessage(), failed);
    }
}

OpaqueTokenAuthenticationProvider 委托 OpaqueTokenIntrospectorintrospect 去校验 token。

PigRedisOAuth2AuthorizationService 通过token value 查询 认证中心下发令牌时 存储的用户认证信息.

image

调用RedisOAuth2AuthorizationServicefindByToken

    @Override
    @Nullable
    public OAuth2Authorization findByToken(String token, @Nullable OAuth2TokenType tokenType) {
        Assert.hasText(token, "token cannot be empty");
        Assert.notNull(tokenType, "tokenType cannot be empty");
        redisTemplate.setValueSerializer(RedisSerializer.java());
        return (OAuth2Authorization) redisTemplate.opsForValue().get(buildKey(tokenType.getValue(), token));
    }

CSDN
腾讯云
掘金
博客园

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容