在使用spring.sercurity.oauth2配置资源服务器时,发现只配置了个ResourceServerConfigurerAdapter的实现类,就可以自己检查token的有效性了,不太理解,百度和debug看了一下源码明白了,大概流程如下
首先我在application.xml中配置了我的认证中心的相关参数
#指定使用的认证中心,如果不配置会使用默认认证中心
security:
oauth2:
client:
client-id: client
client-secret: secret
access-token-uri: http://localhost:9997/oauth/token
user-authorization-uri: http://localhost:9997/oauth/authorize
resource:
token-info-uri: http://localhost:9997/oauth/check_token
当有请求过来请求资源服务器接口时,会被引用的spring.sercurity.oauth2框架接管,被OAuth2AuthenticationProcessingFilter 拦截器拦截,
拦截器源码
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
boolean debug = logger.isDebugEnabled();
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
try {
Authentication authentication = this.tokenExtractor.extract(request);
if (authentication == null) {
if (this.stateless && this.isAuthenticated()) {
if (debug) {
logger.debug("Clearing security context.");
}
SecurityContextHolder.clearContext();
}
if (debug) {
logger.debug("No token in request, will continue chain.");
}
} else {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
if (authentication instanceof AbstractAuthenticationToken) {
AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken)authentication;
needsDetails.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
/*********重点在这里***********/
Authentication authResult = this.authenticationManager.authenticate(authentication);
/****************************/
if (debug) {
logger.debug("Authentication success: " + authResult);
}
this.eventPublisher.publishAuthenticationSuccess(authResult);
SecurityContextHolder.getContext().setAuthentication(authResult);
}
} catch (OAuth2Exception var9) {
SecurityContextHolder.clearContext();
if (debug) {
logger.debug("Authentication request failed: " + var9);
}
this.eventPublisher.publishAuthenticationFailure(new BadCredentialsException(var9.getMessage(), var9), new PreAuthenticatedAuthenticationToken("access-token", "N/A"));
this.authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(var9.getMessage(), var9));
return;
}
chain.doFilter(request, response);
}
进入authenticationManager.authenticate(authentication)发现authenticationManager是个接口,具体实现在OAuth2AuthenticationManager中,
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication == null) {
throw new InvalidTokenException("Invalid token (token not found)");
} else {
String token = (String)authentication.getPrincipal();
/********重点在这里*********/
OAuth2Authentication auth = this.tokenServices.loadAuthentication(token);
/*************************/
if (auth == null) {
throw new InvalidTokenException("Invalid token: " + token);
} else {
Collection<String> resourceIds = auth.getOAuth2Request().getResourceIds();
if (this.resourceId != null && resourceIds != null && !resourceIds.isEmpty() && !resourceIds.contains(this.resourceId)) {
throw new OAuth2AccessDeniedException("Invalid token does not contain resource id (" + this.resourceId + ")");
} else {
this.checkClientDetails(auth);
if (authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails();
if (!details.equals(auth.getDetails())) {
details.setDecodedDetails(auth.getDetails());
}
}
auth.setDetails(authentication.getDetails());
auth.setAuthenticated(true);
return auth;
}
}
}
}
tokenServices也是接口,具体实现在RemoteTokenServices中
public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {
MultiValueMap<String, String> formData = new LinkedMultiValueMap();
formData.add(this.tokenName, accessToken);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", this.getAuthorizationHeader(this.clientId, this.clientSecret));
/***********使用restTemplate发送校验token请求*************/
Map<String, Object> map = this.postForMap(this.checkTokenEndpointUrl, formData, headers);
/*****************************************************/
if (map.containsKey("error")) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("check_token returned error: " + map.get("error"));
}
throw new InvalidTokenException(accessToken);
} else if (!Boolean.TRUE.equals(map.get("active"))) {
this.logger.debug("check_token returned active attribute: " + map.get("active"));
throw new InvalidTokenException(accessToken);
} else {
return this.tokenConverter.extractAuthentication(map);
}
}
到此基本明白资源服务器校验token流程了,其中请求路径的checkTokenEndpointUrl是在资源服务器启动的时候,通过加载appliaction.yml文件读取我配置的认证url加载的
版权声明:本文为qq_38941259原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。