SpringSecurity生成权限流程源码分析
-
自定义match路径,
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/lib/*", "/js/*").permitAll() //配置POST访问/users需要有ADMIN权限 .mvcMatchers(HttpMethod.POST, "/users").hasRole("ADMIN") //允许跨域的所有请求 .mvcMatchers(HttpMethod.OPTIONS).permitAll() //配置GET访问/users所有用户都可以 .mvcMatchers(HttpMethod.GET, "/users").hasAnyRole("ADMIN", "USER") //配置所有请求都需要授权 .anyRequest().authenticated()
-
match调用
authorizeRequests()
创建自定义的ExpressionUrlAuthorizationConfigurer
我们直接从
ExpressionUrlAuthorizationConfigurer
类开始它通过获取默认的
GrantedAuthorityDefaults.class
来定义前缀,但是此类默认不会创建所以我们可以通过创建Bean: GrantedAuthorityDefaults.class来自定义前缀
ExpressionUrlAuthorizationConfigurer在没有 GrantedAuthorityDefaults.class的情况下前缀默认为ROLE_
GrantedAuthorityDefaults类
public final class GrantedAuthorityDefaults { private final String rolePrefix; public GrantedAuthorityDefaults(String rolePrefix) { this.rolePrefix = rolePrefix; } public String getRolePrefix() {return this.rolePrefix; } }
ExpressionUrlAuthorizationConfigurer类
public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) { String[] grantedAuthorityDefaultsBeanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class); if (grantedAuthorityDefaultsBeanNames.length == 1) { GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBean(grantedAuthorityDefaultsBeanNames[0], GrantedAuthorityDefaults.class); this.rolePrefix = grantedAuthorityDefaults.getRolePrefix(); } else { this.rolePrefix = "ROLE_"; } this.REGISTRY = new ExpressionInterceptUrlRegistry(context); }
-
配置match路径时会调用
ExpressionUrlAuthorizationConfigurer
的antMatcher()
方法,该方法通过RequestMatchers.antMatchers(antPatterns)
将传入的antPatterns
封装成List
,最后再把unmappedMatchers
属性设置为该List
和返回一个List
封装的AuthorizedUrl
-
AbstractRequestMatcherRegister
public C antMatchers(String... antPatterns) { return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns)); } protected final C chainRequestMatchers(List<RequestMatcher> requestMatchers) { this.unmappedMatchers = requestMatchers; return chainRequestMatchersInternal(requestMatchers); } protected AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) { return new AuthorizedUrl(requestMatchers); }
RequestMatchers
static List<RequestMatcher> antMatchers(HttpMethod httpMethod, String... antPatterns) { String method = (httpMethod != null) ? httpMethod.toString() : null; List<RequestMatcher> matchers = new ArrayList<>(); for (String pattern : antPatterns) { matchers.add(new AntPathRequestMatcher(pattern, method)); } return matchers; }
-
配置
match
时还会调用ExpressionUrlAuthorizationConfigurer
的mvcMatchers(method, patterns)
方法,该方法调用createMvcMatchers
将method,patterns
封装在一个List<MvcRequestMatcher>
中,继而返回一个封装了List<MvcRequestMatcher>
的MvcMatchersAuthorizedUrl
ExpressionUrlAuthorizationConfigurer
@Override public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) { return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns)); } protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method, String... mvcPatterns) { HandlerMappingIntrospector introspector = this.context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector.class); List<MvcRequestMatcher> matchers = new ArrayList<>(mvcPatterns.length); for (String mvcPattern : mvcPatterns) { MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern); opp.postProcess(matcher); if (method != null) { matcher.setMethod(method); } matchers.add(matcher); } return matchers; }
-
返回的Matchers通过调用permitAll、hasRole、hasAnyRole等方法(全部设置权限的方法可以在AuthorizedUrl中找到)设置权限
我们只分析一个hasRole的源码,如下:
ExpressionUrlAuthorizationConfigurer
spublic ExpressionInterceptUrlRegistry hasRole(String role) { return access(ExpressionUrlAuthorizationConfigurer .hasRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, role)); } //hasRole将前缀和传入的role拼接在一起 private static String hasRole(String rolePrefix, String role) { return "hasRole('" + rolePrefix + role + "')"; } //该方法调用interceptUrl(具体看下面),并返回REGISTRY public ExpressionInterceptUrlRegistry access(String attribute) { interceptUrl(this.requestMatchers, SecurityConfig.createList(attribute)); return ExpressionUrlAuthorizationConfigurer.this.REGISTRY; } //该方法会将所有requestMatchers封装在UrlMapping中并传入REGISTRY private void interceptUrl(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) { for (RequestMatcher requestMatcher : requestMatchers) { this.REGISTRY.addMapping( new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes)); } }
生成权限流程到这里就结束了,至于权限是如何认证的,那就是FilterSecurityIntercepter
的事情了。