Spring Security 访问控制
本文将介绍 Spring Security 的访问控制功能的流程、配置及代码。
一、配置示例
1 |
|
二、配置 - 资源权限信息
1. 开启 URL 匹配模式
1 |
|
2. 在配置类中指定
1 |
|
3. 自定义资源权限信息获取
定义资源权限信息获取类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32@Component
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Autowired
ResourceDao resourceDao;
AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
// 获取要访问的资源 URL
String requestUrl = ((FilterInvocation) object).getRequestUrl();
// 获取所有 Resource,遍历进行路径匹配,匹配成功则返回资源允许访问的角色列表
for (Resource resource : resourceDao.findAll()) {
if (antPathMatcher.match(resource.getUrl(), requestUrl) && resource.getRolesArray().length > 0) {
return SecurityConfig.createList(resource.getRolesArray());
}
}
//匹配不成功,则返回 ROLE_NONE,表示不需要角色即可访问
return SecurityConfig.createList("ROLE_NONE");
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}配置资源权限信息获取类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 开启通过URL匹配从而进行访问控制的模式
.authorizeRequests()
// 首页、登录页、错误页,不需要权限即可访问
.antMatchers("/", "/index", "/login", "/error").permitAll()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O object) {
// 自定义资源及其权限的获取
object.setSecurityMetadataSource(mySecurityMetadataSource);
return object;
}
})
}
4. FilterInvocationSecurityMetadataSource
FilterInvocationSecurityMetadataSource 接口继承自 SecurityMetadataSource 接口。
5. SecurityMetadataSource
主要作用是:根据对象,获取对象所需的权限信息,将权限信息以集合的方式返回。
它的代码大致如下:
1 |
|
三、配置 - 访问控制管理器
1. 配置方式
定义访问控制器类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36@Component
public class MyAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
// 获取当前用户具有的角色
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
// configAttributes 由 SecurityMetadataSource 的 getAttributes() 获取,是资源允许访问的角色列表
for (ConfigAttribute attribute : configAttributes) {
String role = attribute.getAttribute();
// 资源不需要角色,直接 return
if ("ROLE_NONE".equals(role)) {
return;
}
for (GrantedAuthority authority : authorities) {
// 匹配成功,直接 return
if (authority.getAuthority().equals(role)) {
return;
}
}
}
// 匹配失败
throw new AccessDeniedException("你没有访问" + object + "的权限!");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}配置访问控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 开启通过URL匹配从而进行访问控制的模式
.authorizeRequests()
// 首页、登录页、错误页,不需要权限即可访问
.antMatchers("/", "/index", "/login", "/error").permitAll()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O object) {
// 自定义资源的访问控制管理器
object.setAccessDecisionManager(myAccessDecisionManager);
return object;
}
})
}
2. AccessDecisionManager
主要作用是判断用户能否访问指定的资源。
代码如下:
1 |
|
四、配置 - 登录
1 |
|
五、配置 - 登出
1 |
|
六、配置 - 异常处理
定义异常处理类
1
2
3
4
5
6
7
8
9
10
11
12
13@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("拒绝访问:" + accessDeniedException.getMessage());
out.flush();
out.close();
}
}配置异常处理类
1
2http
.exceptionHandling().accessDeniedHandler(异常处理类)