即使授予正确的权限,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);
我的 userDetailsService 填充了 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) 用户正在由 userDetailsService 正确填充。 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 注释。 要么 我改变了我的 userDetailsService:
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 boot oauth2.0 和 spring security:如何通过 facebook 或 slack 授予用户登录权限(权限)