Pig4Cloud之检验token

2022-12-07 14:11:09 浏览数 (2)

## 前端校验请求

/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](https://img2022.cnblogs.com/blog/1901531/202211/1901531-20221124150952640-1953156075.png)

## 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](https://img2022.cnblogs.com/blog/1901531/202211/1901531-20221124143131405-1773364520.png)

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

![image](https://img2022.cnblogs.com/blog/1901531/202211/1901531-20221124143305690-1170185900.png)

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

![image](https://img2022.cnblogs.com/blog/1901531/202211/1901531-20221124144022298-952097594.png)

### 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](https://img2022.cnblogs.com/blog/1901531/202211/1901531-20221124145326378-1962013974.png)

调用`RedisOAuth2AuthorizationService`的`findByToken`

```

@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));

}

```

0 人点赞