Spring Security 自定义后台权限过滤的方案

535 字
3 分钟
Spring Security 自定义后台权限过滤的方案

大概思路#

其实方案有好几种,比如注解权限 @PreAuthorize("hasRole('ROLE_admin') and hasAnyRole('ROLE_user')"),类似这种注解式的,还有在配置里的 hasRole 之类的。

我的其中一种思路#

@Service
@RequiredArgsConstructor
public class InyaaAccessDecisionManager implements AuthorizationManager<RequestAuthorizationContext> {
private final SecurityMetadataSource securityMetadataSource;
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
Collection<ConfigAttribute> collection = this.securityMetadataSource.getAttributes(context);
// 遍历角色
for (ConfigAttribute ca : collection) {
// ① 当前url请求需要的权限
String needRole = ca.getAttribute();
if ("ROLE_ANY".equals(needRole)) {
return new AuthorizationDecision(true);
} else {
// ② 当前用户所具有的角色
Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
for (GrantedAuthority authority : authorities) {
if ("ROLE_ANONYMOUS".equals(authority.getAuthority())) {
return new AuthorizationDecision(false);
} else {
return new AuthorizationDecision(true);
}
}
}
}
return new AuthorizationDecision(false);
}
}
@Service
@RequiredArgsConstructor
public class InyaaFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
private final CacheService cacheService;
/***
* 返回该url所需要的用户权限信息
*
* @param object: 储存请求url信息
* @return: null:标识不需要任何权限都可以访问
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
HttpServletRequest request = ((RequestAuthorizationContext) object).getRequest();
Map<String, Collection<ConfigAttribute>> cacheMap = cacheService.getConfigAttributeMap();
for (String url : cacheMap.keySet()) {
if (new AntPathRequestMatcher(url).matches(request)) {
return cacheMap.get(url);
}
}
throw new AccessDeniedException("当前访问没有权限!");
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return FilterInvocation.class.isAssignableFrom(aClass);
}
}

AuthorizationManager<RequestAuthorizationContext> 主要是对角色的验证,他加载 FilterInvocationSecurityMetadataSource 接口的数据。而 FilterInvocationSecurityMetadataSource 接口主要是做权限的匹配,其中我用到了缓存来加载所有的权限,然后通过 URL 去匹配。

而缓存内的加载大致如下:

public Map<String, Collection<ConfigAttribute>> getConfigAttributeMap() {
if (AuthCache.size() < 1) {
List<InyawSysApi> list = inyawSysApiDao.findAll();
for (InyawSysApi api : list) {
List<ConfigAttribute> configAttributeList = new ArrayList<>();
ConfigAttribute configAttribute;
switch (api.getType()) {
case 0 -> configAttribute = new SecurityConfig("ROLE_ANY");
case 1 -> configAttribute = new SecurityConfig("ROLE_LOGIN");
case 2 -> {
InyawSysRole role = inyawSysRoleService.getById(api.getId());
configAttribute = new SecurityConfig(role.getRoleKey());
}
default -> throw new IllegalStateException("错误的类型: " + api.getType());
}
configAttributeList.add(configAttribute);
AuthCache.put(api.getUrl(), configAttributeList);
}
}
return AuthCache;
}

其余的不多做解释了,代码水平也一般。大概就是 API 表按 type 来判断具体的角色权限,因为我当时没想好具体的权限表如何设计,我现实没这样的需求。

最后是配置类#

http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().access(inyaaAccessDecisionManager)
)
.csrf(AbstractHttpConfigurer::disable)
.oauth2ResourceServer(httpSecurityOAuth2ResourceServerConfigurer ->
httpSecurityOAuth2ResourceServerConfigurer.jwt(Customizer.withDefaults()))
.sessionManagement((session) ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
.accessDeniedHandler(new BearerTokenAccessDeniedHandler())
);

这个配置类是官方 Demo 的 JWT 方案的配置类,权限代码具体有用的就只有前几行 csrf 前边那部分。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
Spring Security 自定义后台权限过滤的方案
https://blog.yuxh.cc/posts/spring-security-custom-authorization/
作者
Firefly
发布于
2026-05-19
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Firefly
Hello, I'm Firefly.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
16
分类
3
标签
30
总字数
16,769
运行时长
0
最后活动
0 天前

文章目录