即使授予正确的权限,Spring Security @Secured 也会拒绝访问

Posted

技术标签:

【中文标题】即使授予正确的权限,Spring Security @Secured 也会拒绝访问【英文标题】:Spring Security @Secured denies access even with correct granted authorities 【发布时间】:2021-10-10 17:43:28 【问题描述】:

我的应用程序是一个 springboot 应用程序 (2.4.0),我在 spring 安全方面遇到了一些问题。我确信它是一些简单的细节,但我就是看不到它。

基本上发生的事情是我从数据库中读取了一个用户“角色”并将其添加到 UserDetails 中的 GrantedAuthorities 列表中。然后我使用@Secured 在控制器中保护我的方法。我已经验证了委托人拥有 GrantedAuthority... 但@Secured 每次都拒绝他们。

配置:

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)

我正在使用 JWT,所以我有一个过滤器可以根据它创建用户:

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException 
    try 
        String jwt = parseJwt(request);
        if (jwt != null && jwtUtils.validateJwtToken(jwt)) 
            String username = jwtUtils.getUserNameFromJwtToken(jwt);

            UserDetails userDetails = userDetailsService.loadUserByUsername(username);

            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            SecurityContextHolder.getContext().setAuthentication(authentication);
        
     catch (Exception e) 
        logger.error("Cannot set user authentication: ", e);
    

    filterChain.doFilter(request, response);

我的 userDetailsS​​ervice 填充了 GrantedAuthorities:

User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));

    Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority(user.getStatus().name()));
    
    return UserDetailsImpl.builder().username(user.getUsername()).guid(user.getGuid()).name(user.getName())
            .password(user.getPassword()).status(user.getStatus()).authorities(authorities).build();

最后是我的安全方法:

@PutMapping("/auth/activate")
@Secured("ROLE_VALIDATING")
public ResponseEntity<?> activateAccount(Authentication authentication) 
    accountService.activateAccount(authentication.getName());
    return ResponseEntity.ok().body(new MessageResponse("Account Activated"));

所以为了解决问题,我继续删除了@Secured 并验证了该方法的执行没有任何问题。然后我关闭了@Secured,并将其添加到方法中以确认它具有授权:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("VALIDATING"))) 
    LOG.info("I has the role!");

果然,当我执行代码时,它会更新我的记录并注销“我有这个角色!”。所以看起来 A) 用户正在由 userDetailsS​​ervice 正确填充。 B) SecurityContextHolder 中的身份验证已正确设置。 C) 用户实际上确实拥有 GrantedAuthority。

但@Secured 仍然拒绝访问。

当我启用调试日志记录时,我会在请求被拒绝时看到以下内容。

初始化 Spring DispatcherServlet 'dispatcherServlet' 初始化 Servlet 'dispatcherServlet' 3 ms 内完成初始化 保护 PUT /api/private/auth/activate 将 SecurityContextHolder 设置为空 SecurityContext 具有属性 [authenticated] 的授权过滤器调用 [PUT /api/private/auth/activate] 安全 PUT /api/private/auth/activate 无法授权 ReflectiveMethodInvocation: public org.springframework.http.ResponseEntity net.theblackchamber.map.dashboard.controller.PrivateController.activateAccount(org.springframework.security.core.Authentication);目标属于 [net.theblackchamber.map.dashboard.controller.PrivateController] 类,具有 [ROLE_VALIDATING] 属性 响应 403 状态码 清除 SecurityContextHolder 以完成请求 保护 PUT /错误 将 SecurityContextHolder 设置为空 SecurityContext 将 SecurityContextHolder 设置为匿名 SecurityContext 安全的 PUT /错误 清除 SecurityContextHolder 以完成请求

【问题讨论】:

您正在测试的GrantedAuthority“VALIDATING”只是一个权限,但您正在测试注释中的“ROLE_VALIDATING”。我不确定@Secured 是否接受授权,我发现的所有示例都是角色。如果您想使用角色,您可能需要测试 @PreAuthorize("hasAuthority('VALIDATING')") 或将权限重命名为“ROLE_VALIDATING”。 还有一个小东西整个早上都在盯着我看!非常感谢。 【参考方案1】:

查看 Ken S 的评论。

您正在测试的 GrantedAuthority “VALIDATING”只是一个权限,但您正在测试注解中的“ROLE_VALIDATING”。我不确定@Secured 是否接受授权,我发现的所有示例都是角色。如果您想使用角色,您可能想要测试 @PreAuthorize("hasAuthority('VALIDATING')") 或将权限重命名为“ROLE_VALIDATING”。 – Ken S 24 分钟前

对于那些跟随我所做的更改的人来说,要么切换到 hasAuthority 和 @PreAuthorize 注释。 要么 我改变了我的 userDetailsS​​ervice:

Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority(String.format("ROLE_%s", user.getStatus())));

相关:Spring Security/Spring Boot - How to set ROLES for users

【讨论】:

以上是关于即使授予正确的权限,Spring Security @Secured 也会拒绝访问的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Security ACL 中授予权限

Spring Security Oauth2 组

使用 Spring Security ACL 授予对现有对象身份的权限

spring boot oauth2.0 和 spring security:如何通过 facebook 或 slack 授予用户登录权限(权限)

如何使用 LDAP 和基于角色的数据库授予权限来实现 Spring Security?

通过 Spring security ldap 对用户进行身份验证时未授予任何权限错误