FrameworkEndpointHandlerMapping
介绍
在Spring Security中,相关的Endpoint定义了一些接口,比如TokenEndpoint的"/oauth/token"可用于登录返回Token信息,但是总有一些特殊需求,比如不希望使用"/oauth/token",而想使用"/login"进行替代。这时候我们就可以通过Spring Security的配置进行实现,而实现就使用到了FrameworkEndpointHandlerMapping。
代码分析
步骤1:配置
笔者自己项目为例,笔者希望获取AccessToken的url用"/oauth2/token/access"替换"/oauth/token", 配置如下:
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.pathMapping("/oauth/token", "/oauth2/token/access")
.pathMapping("/oauth/check_token", "/oauth2/token/check");
}
步骤2:源码分析
代码在AuthorizationServerEndpointsConfigurer这个类当中,putMapping()方法,就是把key value 放到了patternMap这个局部变量当中,frameworkEndpointHandlerMapping()构造实例时,只是把patternMap放到了Mappings里,代码如下:
public final class AuthorizationServerEndpointsConfigurer {
private Map<String, String> patternMap = new HashMap<String, String>();
public AuthorizationServerEndpointsConfigurer pathMapping(String defaultPath, String customPath) {
this.patternMap.put(defaultPath, customPath);
return this;
}
private FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping() {
if (frameworkEndpointHandlerMapping == null) {
frameworkEndpointHandlerMapping = new FrameworkEndpointHandlerMapping();
frameworkEndpointHandlerMapping.setMappings(patternMap);
frameworkEndpointHandlerMapping.setPrefix(prefix);
frameworkEndpointHandlerMapping.setInterceptors(interceptors.toArray());
}
return frameworkEndpointHandlerMapping;
}
}
笔者以ClientCredentialsTokenEndpointFilter为例,我们在AuthorizationServerSecurityConfigurer这个类,创建ClientCredentialsTokenEndpointFilter时,getServletPath()方法是关键。它最终调到getPath(),getPath()代码逻辑就在mapping中进行路径匹配,取出替换的路径,代码如下:
private ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(HttpSecurity http) {
//这里调用了frameworkEndpointHandlerMapping().getServletPath("/oauth/token")
ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter = new ClientCredentialsTokenEndpointFilter(
frameworkEndpointHandlerMapping().getServletPath("/oauth/token"));
clientCredentialsTokenEndpointFilter
.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
authenticationEntryPoint.setTypeName("Form");
authenticationEntryPoint.setRealmName(realm);
clientCredentialsTokenEndpointFilter.setAuthenticationEntryPoint(authenticationEntryPoint);
clientCredentialsTokenEndpointFilter = postProcess(clientCredentialsTokenEndpointFilter);
http.addFilterBefore(clientCredentialsTokenEndpointFilter, BasicAuthenticationFilter.class);
return clientCredentialsTokenEndpointFilter;
}
public class FrameworkEndpointHandlerMapping extends RequestMappingHandlerMapping {
private Map<String, String> mappings = new HashMap<String, String>();
public String getServletPath(String defaultPath) {
return (prefix == null ? "" : prefix) + getPath(defaultPath);
}
public String getPath(String defaultPath) {
String result = defaultPath;
if (mappings.containsKey(defaultPath)) {
result = mappings.get(defaultPath);
}
return result;
}
}