Spring Security - 授权


Spring Security - 授权
指定角色才能访问特定的资源
实现逻辑大体如下:
先定义指定资源都有哪些角色可以访问,用户登录后,获取到用户的所有角色。
然后看资源的角色中是否包含了用户的角色,如果有,则可以访问,否则,则不能访问。
我们扩展 AbstractSecurityInterceptor 方法类,类中定义的 FilterSourceMetadataSource 的作用
就是获取当前资源的可访问的角色
定义的 MyAccessDecisionManager 就是遍历资源的角色是否包含用户的角色,如果包含,则是可以访问的。
修改 WebSecurityConfig 文件
@Autowired
private MySecurityFilter mySecurityFilter;
在 protected void configure(HttpSecurity http) 方法中添加
http.addFilterBefore(mySecurityFilter, FilterSecurityInterceptor.class)
MySecurityFilter.java 文件的内容如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.servlet.*;
import java.io.IOException;
@Service
public class MySecurityFilter extends AbstractSecurityInterceptor implements Filter {
@Autowired
private FilterSourceMetadataSource filterSourceMetadataSource;
@Autowired
private MyAccessDecisionManager myAccessDecisionManager;
@PostConstruct
public void init(){
//super.setAuthenticationManager(authenticationManager);
super.setAccessDecisionManager(myAccessDecisionManager);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation( request, response, chain );
InterceptorStatusToken token = super.beforeInvocation(fi);
try{
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}finally{
super.afterInvocation(token, null);
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.filterSourceMetadataSource;
}
}
FilterSourceMetadataSource.java 文件的内容如下:
package com.example.demo.security.access;
import com.example.demo.model.userInfo.ResourceRole;
import com.example.demo.service.ResourceRoleService;
import com.example.demo.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Service
public class FilterSourceMetadataSource implements FilterInvocationSecurityMetadataSource {
@Autowired
private ResourceRoleService resourceRoleService;
@Override
//接收用户请求的地址,返回访问该地址需要的所有权限
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
//得到用户的请求地址,控制台输出一下
// String requestUrl = ((FilterInvocation) object).getRequestUrl();
// System.out.println("用户请求的地址是:" + requestUrl);
//
// if (requestUrl.equalsIgnoreCase("/user/info")) {
// return SecurityConfig.createList("role1", "role2");
// }
HttpServletRequest request = ((FilterInvocation) object).getRequest();
Collection<ConfigAttribute> cList = new ArrayList<>();
List<ResourceRole> list = getResourceRole();
for (ResourceRole rr : list) {
String[] apis = rr.getApis().split(";");
for (String api : apis) {
if (StringUtils.isEmpty(api)) {
continue;
}
AntPathRequestMatcher matcher = new AntPathRequestMatcher(api);
if (matcher.matches(request)) {
cList.add(new SecurityConfig(rr.getRoleName()));
}
}
}
if (cList.size() > 0) {
return cList;
}
else {
//throw new AccessDeniedException("请设置权限");
return null;
}
//return cList;
//无权限限制
//return null;
}
private List<ResourceRole> getResourceRole() {
return resourceRoleService.getAll();
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
// 要修改为true,否则会提示 SecurityMetadataSource does not support secure object class: class org.springframework.security.web.FilterInvocation
return true;
}
}
这里的资源角色是这样对应的 /boat/;/boatDetail/ -> 角色admin
因此要查资源的角色需要先将;分割,然后看是否匹配,匹配的话,得到角色信息
MyAccessDecisionManager.java 文件的内容如下:
package com.example.demo.security.access;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Collection;
@Service
public class MyAccessDecisionManager implements AccessDecisionManager {
/*
* @param authentication 当前用户
*
* @param object 要访问的资源
*
* @param configAttributes 安全对象关联的配置属性
* //Security需要用到一个实现了AccessDecisionManager接口的类
//类功能:根据当前用户的信息,和目标url涉及到的权限,判断用户是否可以访问
//判断规则:用户只要匹配到目标url权限中的一个role就可以访问
*/
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if (configAttributes == null)
return;
for (ConfigAttribute configAttribute : configAttributes) {
String attribute = configAttribute.getAttribute();
for (GrantedAuthority authority : authentication.getAuthorities()) {
if(authority.getAuthority().equals(attribute))
return;
}
}
throw new AccessDeniedException("权限不足");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return false;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
自定义没有权限页面
http.exceptionHandling()
.accessDeniedHandler(customAccessDeniedHandler)
.authenticationEntryPoint(new CustomAuthenticationEntryPoint());
扫码分享
版权说明
作者:SQBER
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
{0}
{5}
{1}
{2}回复
{4}
*昵称:
*邮箱:
个人站点:
*想说的话: