问题描述
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests();
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry1 = http.authorizeRequests();
http.authorizeRequests()
// .antMatchers(PERMIT_ALL_MAPPING)
// .permitAll()
.antMatchers( "/api/data")
// USER 和 ADMIN 都可以访问
.hasAnyAuthority(USER)
.antMatchers("/api/user/**", "/api/logout")
// USER 和 ADMIN 都可以访问
.hasAnyAuthority("all")
// .hasAnyAuthority("all")// 允许所有权限
.antMatchers("/api/admin/**", "/api/**")
// 只有 ADMIN 才可以访问
.hasAnyAuthority(ADMIN, USER, "asdfasd")
.anyRequest()
.authenticated()
.and()
// 添加过滤器链,前一个参数过滤器, 后一个参数过滤器添加的地方
// 登陆过滤器
.addFilterBefore(new JwtLoginFilter("/api/login", authenticationManager(), loginCountService), UsernamePasswordAuthenticationFilter.class)
// 请求过滤器
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
// 开启跨域
.cors()
.and()
// 开启 csrf
.csrf()
.disable()
// .ignoringAntMatchers(PERMIT_ALL_MAPPING)
// .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// .and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
按照上述方式配置权限,一个具有ADMIN权限的账户访问/api/data接口时是否能够成功?
观点1:/api/data接口符合这段配置,所以应该仅限USER权限才能访问
.antMatchers( "/api/data")
// USER 和 ADMIN 都可以访问
.hasAnyAuthority(USER)
观点2:/api/data接口符合这段配置,ADMIN权限可以访问
.antMatchers("/api/admin/**", "/api/**")
// 只有 ADMIN 才可以访问
.hasAnyAuthority(ADMIN, USER, "asdfasd")
观点1和观点2冲突
结论
无法访问。程序会按照下面的对/api/data这个请求仅限校验。
.antMatchers( "/api/data")
// USER 和 ADMIN 都可以访问
.hasAnyAuthority(USER)
当一个url匹配多个规则时,先配置的规则有效。先配置的那个规则校验成功,那么就有权限访问资源,否则就没有权限访问资源。
此外,若antMatchers中有完全一模一样的url同时被配置多次,且权限不同,程序会按照最后那个为准。
比如下面这段代码把/api/data的权限配置了三次,当运行时会按照(ADMIN, USER, “asdfasd”)仅限权限校验。
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests();
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry1 = http.authorizeRequests();
http.authorizeRequests()
// .antMatchers(PERMIT_ALL_MAPPING)
// .permitAll()
.antMatchers( "/api/data")
// USER 和 ADMIN 都可以访问
.hasAnyAuthority(USER)
.antMatchers("/api/data")
// USER 和 ADMIN 都可以访问
.hasAnyAuthority("all")
// .hasAnyAuthority("all")// 允许所有权限
.antMatchers("/api/data")
// 只有 ADMIN 才可以访问
.hasAnyAuthority(ADMIN, USER, "asdfasd")
.anyRequest()
.authenticated()
.and()
// 添加过滤器链,前一个参数过滤器, 后一个参数过滤器添加的地方
// 登陆过滤器
.addFilterBefore(new JwtLoginFilter("/api/login", authenticationManager(), loginCountService), UsernamePasswordAuthenticationFilter.class)
// 请求过滤器
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
// 开启跨域
.cors()
.and()
// 开启 csrf
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
代码分析
初始化阶段将配置的权限信息保存成一个list,然后根据list生成map。处理请求时根据map校验权限。
生成list
根据配置生成org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry#urlMappings这个list
调用org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry#addMapping(org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry.UrlMapping)将配置中的权限信息设置到list中
生成map
应用启动时根据list生成org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource#requestMap这个map
先调用org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry#createRequestMap将list转换成map
然后调用org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource#DefaultFilterInvocationSecurityMetadataSource将数据设置到org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource#requestMap,以便之后对请求进行权限校验
根据map判断权限
org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource#getAttributes