spring security经常在项目中用到,但是平常只是简单的使用肯定是不够的,我们需要了解深层次的东西,才能在使用的过程中不畏惧,本次打算从demo入手,跟踪源码,剖析security内在
一、@FrameworkEndpoint注解的作用
1、在之前的文章中我们看到AuthorizationServerEndpointsConfiguration配置中配置了AuthorizationEndpoint和TokenEndpoint等,他们都是继承自AbstractEndpoint 2、AuthorizationServerEndpointsConfiguration中创建了FrameworkEndpointHandlerMapping 这个RequestMappingHandlerMapping大家应该比较熟悉了,是mvc中的加载handler的类 现在我们看下FrameworkEndpointHandlerMapping的isHandler方法 至此应该清楚了,就是类上注解@FrameworkEndpoint的存在,将各个AbstractEndpoint的方法加载到servlet中
二、oauth/token请求参数如何封装成了Principal
clent的认证我们上一篇文章中已经讲过了,现在我们继续剖析这个获取token的接口 首先我们倒推看下mvc中参数是如何解析并封装到方法中的
1、ServletRequestMethodArgumentResolver参数解析
@Nullable
private Object resolveArgument(Class<?> paramType, HttpServletRequest request) throws IOException {
if (HttpSession.class.isAssignableFrom(paramType)) {
HttpSession session = request.getSession();
if (session != null && !paramType.isInstance(session)) {
throw new IllegalStateException(
"Current session is not of type [" + paramType.getName() + "]: " + session);
}
return session;
}
...
...
else if (Principal.class.isAssignableFrom(paramType)) {
Principal userPrincipal = request.getUserPrincipal();
if (userPrincipal != null && !paramType.isInstance(userPrincipal)) {
throw new IllegalStateException(
"Current user principal is not of type [" + paramType.getName() + "]: " + userPrincipal);
}
return userPrincipal;
}
else if (HttpMethod.class == paramType) {
return HttpMethod.resolve(request.getMethod());
}
...
throw new UnsupportedOperationException("Unknown parameter type: " + paramType.getName());
}
从request中获取principal,此时的request的是
2、SecurityContextHolderAwareRequestFilter过滤器创建流程见下图
3、SecurityContextHolderAwareRequestFilter执行流程
小结
由于Servlet3SecurityContextHolderAwareRequestWrapper继承自SecurityContextHolderAwareRequestWrapper 回到参数解析流程,调用了request的getUserPrincipal方法,看下SecurityContextHolderAwareRequestWrapper的getUserPrincipal方法 至此返回了认证对象Authentication
三、grant过程
@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
"There is no client authentication. Try adding an appropriate authentication filter.");
}
String clientId = getClientId(principal);
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
if (clientId != null && !clientId.equals("")) {
if (!clientId.equals(tokenRequest.getClientId())) {
throw new InvalidClientException("Given client ID does not match authenticated client");
}
}
...
...
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
return getResponse(token);
}
此时的tokenGranter是AuthorizationServerEndpointsConfigurer的tokenGranter创建的匿名对象 默认5种授权类型(授权码模式(authorization_code)、刷新令牌(refresh_token)、简化模式(implicit)、客户端模式(client credentials)、密码模式(password)
|