You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security中@PreAuthorize的其他校验方式:方法内如何实现?

在方法内部实现Spring Security权限校验的几种方式

你当前通过@PreAuthorize注解实现权限校验的写法如下:

@PreAuthorize("hasRole('ADMIN') or hasAuthority('GET_BOOK')")
@PostMapping("/find")
public Pagination<BookDTO> find(@Valid @RequestBody QueryCriteria queryCriteria) {
    return bookService.find(queryCriteria);
}

如果需要在方法内部完成权限校验,以下是几种可行方案:

方案一:通过SecurityContextHolder手动校验权限

直接获取当前用户的认证信息,遍历权限集合判断是否符合要求:

@PostMapping("/find")
public Pagination<BookDTO> find(@Valid @RequestBody QueryCriteria queryCriteria) {
    // 获取当前用户的认证信息
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    // 校验是否拥有ADMIN角色(注意Spring Security中hasRole对应权限前缀为ROLE_)或GET_BOOK权限
    boolean hasPermission = authentication.getAuthorities().stream()
            .anyMatch(auth -> "ROLE_ADMIN".equals(auth.getAuthority()) || "GET_BOOK".equals(auth.getAuthority()));

    if (!hasPermission) {
        throw new AccessDeniedException("无权限访问该接口");
    }

    return bookService.find(queryCriteria);
}

方案二:使用AuthorizationManager(Spring Security 6+推荐)

借助框架提供的AuthorizationManager组件,更规范地实现权限校验:

@Autowired
private AuthorizationManager<AuthorizationContext> authorizationManager;

@PostMapping("/find")
public Pagination<BookDTO> find(@Valid @RequestBody QueryCriteria queryCriteria) {
    // 构建权限校验规则:匹配ROLE_ADMIN或GET_BOOK权限
    AuthorizationDecision decision = authorizationManager.check(
            () -> SecurityContextHolder.getContext().getAuthentication(),
            AuthorityAuthorizationManager.hasAnyAuthority("ROLE_ADMIN", "GET_BOOK")
    );

    if (!decision.isGranted()) {
        throw new AccessDeniedException("无权限访问该接口");
    }

    return bookService.find(queryCriteria);
}

方案三:复用SecurityExpressionRoot的逻辑

通过表达式处理器获取SecurityExpressionRoot,直接调用和@PreAuthorize中一致的方法:

@Autowired
private SecurityExpressionHandler<FilterInvocation> expressionHandler;
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;

@PostMapping("/find")
public Pagination<BookDTO> find(@Valid @RequestBody QueryCriteria queryCriteria) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    FilterInvocation filterInvocation = new FilterInvocation(request, response, null);
    SecurityExpressionRoot expressionRoot = expressionHandler.createSecurityExpressionRoot(authentication, filterInvocation);

    // 和注解中完全一致的校验逻辑
    boolean hasPermission = expressionRoot.hasRole("ADMIN") || expressionRoot.hasAuthority("GET_BOOK");

    if (!hasPermission) {
        throw new AccessDeniedException("无权限访问该接口");
    }

    return bookService.find(queryCriteria);
}

各方案说明

  • 方案一:最轻量化,无需额外注入组件,但需要手动处理权限字符串的前缀规则,适合简单场景。
  • 方案二:Spring Security 6+官方推荐的权限校验方式,支持复杂规则组合,扩展性更好。
  • 方案三:完全复用注解中的SpEL表达式逻辑,减少代码差异,但需要依赖请求响应对象,相对繁琐。

内容的提问来源于stack exchange,提问作者Tuấn Nguyễn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 11:48:36