Table of Contents
505 words
3 minutes
Spring Security 自定义后台权限过滤的方案
大概思路
方案有好几种,比如注解式的 @PreAuthorize("hasRole('ROLE_admin') and hasAnyRole('ROLE_user')"),或者在配置里写 hasRole。
我的其中一种思路
1@Service2@RequiredArgsConstructor3public class InyaaAccessDecisionManager implements AuthorizationManager<RequestAuthorizationContext> {4
5 private final SecurityMetadataSource securityMetadataSource;6
7 @Override8 public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {9 Collection<ConfigAttribute> collection = this.securityMetadataSource.getAttributes(context);10 // 遍历角色11 for (ConfigAttribute ca : collection) {12 // ① 当前url请求需要的权限13 String needRole = ca.getAttribute();14 if ("ROLE_ANY".equals(needRole)) {15 return new AuthorizationDecision(true);16 } else {17 // ② 当前用户所具有的角色18 Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();19 for (GrantedAuthority authority : authorities) {20 if ("ROLE_ANONYMOUS".equals(authority.getAuthority())) {21 return new AuthorizationDecision(false);22 } else {23 return new AuthorizationDecision(true);24 }25 }26 }27 }28 return new AuthorizationDecision(false);29 }30}1@Service2@RequiredArgsConstructor3public class InyaaFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {4
5 private final CacheService cacheService;6
7 /***8 * 返回该url所需要的用户权限信息9 *10 * @param object: 储存请求url信息11 * @return: null:标识不需要任何权限都可以访问12 */13 @Override14 public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {15 HttpServletRequest request = ((RequestAuthorizationContext) object).getRequest();16 Map<String, Collection<ConfigAttribute>> cacheMap = cacheService.getConfigAttributeMap();17 for (String url : cacheMap.keySet()) {18 if (new AntPathRequestMatcher(url).matches(request)) {19 return cacheMap.get(url);20 }21 }22 throw new AccessDeniedException("当前访问没有权限!");23 }24
25 @Override26 public Collection<ConfigAttribute> getAllConfigAttributes() {27 return null;28 }29
30 @Override31 public boolean supports(Class<?> aClass) {32 return FilterInvocation.class.isAssignableFrom(aClass);33 }34}AuthorizationManager<RequestAuthorizationContext> 主要是对角色的验证,他加载 FilterInvocationSecurityMetadataSource 接口的数据。而 FilterInvocationSecurityMetadataSource 接口主要是做权限的匹配,其中我用到了缓存来加载所有的权限,然后通过 URL 去匹配。
而缓存内的加载大致如下:
1public Map<String, Collection<ConfigAttribute>> getConfigAttributeMap() {2 if (AuthCache.size() < 1) {3 List<InyawSysApi> list = inyawSysApiDao.findAll();4 for (InyawSysApi api : list) {5 List<ConfigAttribute> configAttributeList = new ArrayList<>();6 ConfigAttribute configAttribute;7 switch (api.getType()) {8 case 0 -> configAttribute = new SecurityConfig("ROLE_ANY");9 case 1 -> configAttribute = new SecurityConfig("ROLE_LOGIN");10 case 2 -> {11 InyawSysRole role = inyawSysRoleService.getById(api.getId());12 configAttribute = new SecurityConfig(role.getRoleKey());13 }14 default -> throw new IllegalStateException("错误的类型: " + api.getType());15 }16 configAttributeList.add(configAttribute);17 AuthCache.put(api.getUrl(), configAttributeList);18 }19 }20 return AuthCache;21}其余就不多解释了,代码水平也一般。大概就是 API 表的 type 字段决定权限类型——当时没想好具体的权限表设计,实际也没这个需求。
最后是配置类
1http2 .authorizeHttpRequests((authorize) -> authorize3 .anyRequest().access(inyaaAccessDecisionManager)4 )5 .csrf(AbstractHttpConfigurer::disable)6 .oauth2ResourceServer(httpSecurityOAuth2ResourceServerConfigurer ->7 httpSecurityOAuth2ResourceServerConfigurer.jwt(Customizer.withDefaults()))8 .sessionManagement((session) ->9 session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))10 .exceptionHandling((exceptions) -> exceptions11 .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())12 .accessDeniedHandler(new BearerTokenAccessDeniedHandler())13 );这个配置类基本是官方 Demo 的 JWT 方案,真正管权限的也就 csrf 前面那几行。
Spring Security 自定义后台权限过滤的方案
/posts/guide/spring-security-custom-authorization/ Some information may be outdated