Spring Security - 授权

时间 2021/5/30 20:09:05 加载中...

Spring Security - 授权

指定角色才能访问特定的资源

实现逻辑大体如下:

先定义指定资源都有哪些角色可以访问,用户登录后,获取到用户的所有角色。
然后看资源的角色中是否包含了用户的角色,如果有,则可以访问,否则,则不能访问。

我们扩展 AbstractSecurityInterceptor 方法类,类中定义的 FilterSourceMetadataSource 的作用
就是获取当前资源的可访问的角色

定义的 MyAccessDecisionManager 就是遍历资源的角色是否包含用户的角色,如果包含,则是可以访问的。

修改 WebSecurityConfig 文件

  1. @Autowired
  2. private MySecurityFilter mySecurityFilter;
  3. protected void configure(HttpSecurity http) 方法中添加
  4. http.addFilterBefore(mySecurityFilter, FilterSecurityInterceptor.class)

MySecurityFilter.java 文件的内容如下:

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.security.access.SecurityMetadataSource;
  3. import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
  4. import org.springframework.security.access.intercept.InterceptorStatusToken;
  5. import org.springframework.security.web.FilterInvocation;
  6. import org.springframework.stereotype.Service;
  7. import javax.annotation.PostConstruct;
  8. import javax.servlet.*;
  9. import java.io.IOException;
  10. @Service
  11. public class MySecurityFilter extends AbstractSecurityInterceptor implements Filter {
  12. @Autowired
  13. private FilterSourceMetadataSource filterSourceMetadataSource;
  14. @Autowired
  15. private MyAccessDecisionManager myAccessDecisionManager;
  16. @PostConstruct
  17. public void init(){
  18. //super.setAuthenticationManager(authenticationManager);
  19. super.setAccessDecisionManager(myAccessDecisionManager);
  20. }
  21. @Override
  22. public void init(FilterConfig filterConfig) throws ServletException {
  23. // TODO Auto-generated method stub
  24. }
  25. @Override
  26. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  27. throws IOException, ServletException {
  28. FilterInvocation fi = new FilterInvocation( request, response, chain );
  29. InterceptorStatusToken token = super.beforeInvocation(fi);
  30. try{
  31. fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
  32. }finally{
  33. super.afterInvocation(token, null);
  34. }
  35. }
  36. @Override
  37. public void destroy() {
  38. // TODO Auto-generated method stub
  39. }
  40. @Override
  41. public Class<?> getSecureObjectClass() {
  42. return FilterInvocation.class;
  43. }
  44. @Override
  45. public SecurityMetadataSource obtainSecurityMetadataSource() {
  46. return this.filterSourceMetadataSource;
  47. }
  48. }

FilterSourceMetadataSource.java 文件的内容如下:

  1. package com.example.demo.security.access;
  2. import com.example.demo.model.userInfo.ResourceRole;
  3. import com.example.demo.service.ResourceRoleService;
  4. import com.example.demo.service.RoleService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.security.access.AccessDeniedException;
  7. import org.springframework.security.access.ConfigAttribute;
  8. import org.springframework.security.access.SecurityConfig;
  9. import org.springframework.security.web.FilterInvocation;
  10. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
  11. import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
  12. import org.springframework.stereotype.Service;
  13. import org.springframework.util.StringUtils;
  14. import javax.servlet.http.HttpServletRequest;
  15. import java.util.ArrayList;
  16. import java.util.Collection;
  17. import java.util.List;
  18. @Service
  19. public class FilterSourceMetadataSource implements FilterInvocationSecurityMetadataSource {
  20. @Autowired
  21. private ResourceRoleService resourceRoleService;
  22. @Override
  23. //接收用户请求的地址,返回访问该地址需要的所有权限
  24. public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
  25. //得到用户的请求地址,控制台输出一下
  26. // String requestUrl = ((FilterInvocation) object).getRequestUrl();
  27. // System.out.println("用户请求的地址是:" + requestUrl);
  28. //
  29. // if (requestUrl.equalsIgnoreCase("/user/info")) {
  30. // return SecurityConfig.createList("role1", "role2");
  31. // }
  32. HttpServletRequest request = ((FilterInvocation) object).getRequest();
  33. Collection<ConfigAttribute> cList = new ArrayList<>();
  34. List<ResourceRole> list = getResourceRole();
  35. for (ResourceRole rr : list) {
  36. String[] apis = rr.getApis().split(";");
  37. for (String api : apis) {
  38. if (StringUtils.isEmpty(api)) {
  39. continue;
  40. }
  41. AntPathRequestMatcher matcher = new AntPathRequestMatcher(api);
  42. if (matcher.matches(request)) {
  43. cList.add(new SecurityConfig(rr.getRoleName()));
  44. }
  45. }
  46. }
  47. if (cList.size() > 0) {
  48. return cList;
  49. }
  50. else {
  51. //throw new AccessDeniedException("请设置权限");
  52. return null;
  53. }
  54. //return cList;
  55. //无权限限制
  56. //return null;
  57. }
  58. private List<ResourceRole> getResourceRole() {
  59. return resourceRoleService.getAll();
  60. }
  61. @Override
  62. public Collection<ConfigAttribute> getAllConfigAttributes() {
  63. return null;
  64. }
  65. @Override
  66. public boolean supports(Class<?> clazz) {
  67. // 要修改为true,否则会提示 SecurityMetadataSource does not support secure object class: class org.springframework.security.web.FilterInvocation
  68. return true;
  69. }
  70. }

这里的资源角色是这样对应的 /boat/;/boatDetail/ -> 角色admin
因此要查资源的角色需要先将;分割,然后看是否匹配,匹配的话,得到角色信息

MyAccessDecisionManager.java 文件的内容如下:

  1. package com.example.demo.security.access;
  2. import org.springframework.security.access.AccessDecisionManager;
  3. import org.springframework.security.access.AccessDeniedException;
  4. import org.springframework.security.access.ConfigAttribute;
  5. import org.springframework.security.authentication.InsufficientAuthenticationException;
  6. import org.springframework.security.core.Authentication;
  7. import org.springframework.security.core.GrantedAuthority;
  8. import org.springframework.stereotype.Service;
  9. import java.util.Collection;
  10. @Service
  11. public class MyAccessDecisionManager implements AccessDecisionManager {
  12. /*
  13. * @param authentication 当前用户
  14. *
  15. * @param object 要访问的资源
  16. *
  17. * @param configAttributes 安全对象关联的配置属性
  18. * //Security需要用到一个实现了AccessDecisionManager接口的类
  19. //类功能:根据当前用户的信息,和目标url涉及到的权限,判断用户是否可以访问
  20. //判断规则:用户只要匹配到目标url权限中的一个role就可以访问
  21. */
  22. @Override
  23. public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
  24. throws AccessDeniedException, InsufficientAuthenticationException {
  25. if (configAttributes == null)
  26. return;
  27. for (ConfigAttribute configAttribute : configAttributes) {
  28. String attribute = configAttribute.getAttribute();
  29. for (GrantedAuthority authority : authentication.getAuthorities()) {
  30. if(authority.getAuthority().equals(attribute))
  31. return;
  32. }
  33. }
  34. throw new AccessDeniedException("权限不足");
  35. }
  36. @Override
  37. public boolean supports(ConfigAttribute attribute) {
  38. return false;
  39. }
  40. @Override
  41. public boolean supports(Class<?> clazz) {
  42. return true;
  43. }
  44. }

自定义没有权限页面

  1. http.exceptionHandling()
  2. .accessDeniedHandler(customAccessDeniedHandler)
  3. .authenticationEntryPoint(new CustomAuthenticationEntryPoint());
扫码分享
版权说明
作者:SQBER
文章来源:http://www.sqber.com/articles/spring-security-authorize.html
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。