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 委托 OpaqueTokenIntrospector introspect 去校验 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));
	}
posted @ 2022-11-24 15:09  leepandar  阅读(129)  评论(0编辑  收藏  举报