SpringSecurity 进行自定义Token校验

本文介绍了在Spring Security中如何进行自定义Token校验,适用于需要使用Token进行权限控制的场景。通过创建自定义的TokenAuthentication、AuthenticationTokenFilter、SecurityPermissionEvaluator以及SecurityConfig,实现了从接收请求到权限验证的全过程。详细讲解了每个关键组件的作用和实现方法,为读者提供了自定义Spring Security鉴权的实践参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

Spring Security默认使用「用户名/密码」的方式进行登陆校验,并通过cookie的方式存留登陆信息。在一些定制化场景,比如希望单独使用token串进行部分页面的访问权限控制时,默认方案无法支持。在未能在网上搜索出相关实践的情况下,通过官方文档及个别Stack Overflow的零散案例,形成整体思路并实践测试通过,本文即关于该方案的一个分享。

参考

官方文档:https://docs.spring.io/spring-security/site/docs/5.0.5.BUILD-SNAPSHOT/reference/htmlsingle/

SpringSecurity校验流程

基本的SpringSecurity使用方式网上很多,不是本文关注的重点,如有需要可以自行搜索或参见https://blog.youkuaiyun.com/u012702547/article/details/54319508

关于校验的整个流程简单的说,整个链路有三个关键点,

  • 将需要鉴权的类/方法/url),定义为需要鉴权(本文代码示例为方法上注解@PreAuthorize("hasPermission('TARGET','PERMISSION')")
  • 根据访问的信息产生一个来访者的权限信息Authentication,并插入到上下文中
  • 在调用鉴权方法时,根据指定的鉴权方式,验证权限信息是否符合权限要求

完整的调用链建议在IDE中通过单步调试亲自体会,本文不做相关整理。

如何自定义

我的需求,是使用自定义的token,验证权限,涉及到:

  • 产生Authentication并插入到上下文中
  • 针对token的验证方式

需要做的事情如下:

  • 自定义TokenAuthentication类,实现org.springframework.security.core.Authenticaion,作为token权限信息
  • 自定义AuthenticationTokenFilter类,实现javax.servlet.Filter,在收到访问时,根据访问信息生成TokenAuthentication实例,并插入上下文
  • 自定义SecurityPermissionEvalutor类,实现org.springframework.security.access.PermissionEvaluator,完成权限的自定义验证逻辑
  • 在全局的配置中,定义使用SecurityPermissionEvalutor作为权限校验方式

TokenAuthentication.java

/**
 * @author: Blaketairan
 */

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import java
<think>好的,用户想了解如何在Spring Security中实现自定义权限校验。我之前回答过类似的问题,需要参考提供的引用内容。先看看引用里的信息。 引用1提到OAuth2AuthorizationService的配置方式,有通过注册Bean和使用配置类的方法。不过这可能和权限校验关系不大,可能更多是授权服务器的配置。引用2中的MySecurityService类展示了如何通过自定义的权限服务来检查用户权限,这里用到了Authentication对象和GrantedAuthority。引用3详细说明了自定义FilterSecurityInterceptor需要配置accessDecisionManager、fisMetadataSource等组件,并提到了decide方法的作用。 用户的问题是关于自定义权限校验的,所以需要结合这些引用中的信息。可能需要以下步骤: 1. 实现自定义的权限校验逻辑,比如使用@PreAuthorize注解结合自定义的权限检查方法,如引用2中的hasPermission方法。这样可以在方法级别进行权限控制。 2. 配置自定义的安全拦截器,如引用3提到的myFilterSecurityInterceptor,需要创建并配置accessDecisionManager和securityMetadataSource。这里可能需要自定义投票器或者决策管理器,以决定是否允许访问资源。 3. 可能需要扩展GrantedAuthority,自定义权限的表示方式,比如使用特定的字符串或对象。 需要注意,用户可能需要具体的代码示例和配置步骤。需要分步骤讲解,包括如何创建自定义权限校验服务、如何集成到Spring Security的配置中,以及如何在实际应用中使用这些自定义权限。 另外,要确保回答结构清晰,步骤明确,并包含代码示例,比如自定义的AccessDecisionVoter或者使用SpEL表达式进行权限校验。还要考虑是否需要覆盖默认的权限配置,或者与现有的权限管理结合使用。 可能需要提到两种主要方式:一种是使用表达式注解(如@PreAuthorize),另一种是自定义投票器和决策管理器。这样用户可以根据需求选择合适的方法。同时,需要参考引用中的代码示例,例如如何从Authentication中获取权限,如何实现权限判断逻辑。 最后,生成相关问题,帮助用户深入理解,比如如何动态管理权限,如何处理复杂的权限逻辑等。</think>在Spring Security中实现自定义权限校验可通过以下三种方式实现,以下步骤结合动态权限管理和安全拦截器配置进行说明: ### 一、基于表达式的方法级权限控制 1. 创建权限校验服务类,继承`SecurityExpressionRoot`并实现自定义逻辑: ```java @Component("myAuth") public class CustomAuthService { public boolean checkProjectAccess(Long projectId) { // 从数据库/缓存获取权限数据 return projectService.hasAccess(SecurityUtils.getCurrentUser(), projectId); } } ``` 2. 在Security配置中启用方法级注解: ```java @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { @Override protected MethodSecurityExpressionHandler createExpressionHandler() { DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler(); handler.setPermissionEvaluator(new CustomPermissionEvaluator()); return handler; } } ``` 3. 在Controller层使用校验: ```java @PreAuthorize("@myAuth.checkProjectAccess(#projectId)") @GetMapping("/projects/{projectId}") public Project getProject(@PathVariable Long projectId) { //... } ``` ### 二、自定义投票器实现 1. 实现`AccessDecisionVoter`接口: ```java public class CustomVoter implements AccessDecisionVoter<FilterInvocation> { @Override public boolean supports(ConfigAttribute attribute) { return attribute.getAttribute().startsWith("CUSTOM_"); } @Override public int vote(Authentication auth, FilterInvocation fi, Collection<ConfigAttribute> attributes) { String requestURI = fi.getRequest().getRequestURI(); return checkAccess(auth, requestURI) ? ACCESS_GRANTED : ACCESS_DENIED; } } ``` 2. 配置决策管理器: ```java @Bean public AccessDecisionManager accessDecisionManager() { List<AccessDecisionVoter<?>> voters = new ArrayList<>(); voters.add(new WebExpressionVoter()); voters.add(new CustomVoter()); return new UnanimousBased(voters); } ``` ### 三、动态元数据源配置 1. 实现`FilterInvocationSecurityMetadataSource`: ```java public class DynamicMetadataSource implements FilterInvocationSecurityMetadataSource { @Override public Collection<ConfigAttribute> getAttributes(Object object) { FilterInvocation fi = (FilterInvocation) object; String url = fi.getRequestUrl(); // 从数据库动态加载权限配置 return loadAttributesFromDB(url); } } ``` 2. 配置安全拦截器: ```java @Bean public FilterSecurityInterceptor customFilter() throws Exception { FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor(); interceptor.setAccessDecisionManager(accessDecisionManager()); interceptor.setSecurityMetadataSource(metadataSource()); interceptor.setAuthenticationManager(authenticationManager); return interceptor; } ``` ### 四、权限上下文集成 在JWT认证场景中,可在`JwtAuthenticationFilter`解析时注入权限: ```java public class JwtFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { String token = extractToken(request); Claims claims = parseToken(token); List<GrantedAuthority> authorities = convertClaimsToAuthorities(claims); Authentication auth = new JwtAuthenticationToken(claims.getSubject(), authorities); SecurityContextHolder.getContext().setAuthentication(auth); } } ``` ### 性能优化建议 1. 权限缓存:使用`@Cacheable`注解缓存权限数据 ```java @Cacheable(value = "userPermissions", key = "#userId") public Set<String> getUserPermissions(Long userId) { // 数据库查询 } ``` 2. 批量查询:在`loadAttributesFromDB`方法中使用IN语句批量获取URL权限配置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值