【问题标题】:@PreAuthorize returns 403@PreAuthorize 返回 403
【发布时间】:2020-10-14 08:10:18
【问题描述】:

我在控制器中有如下方法

@GetMapping("/hello")
@PreAuthorize("hasRole('ADMIN')")
public String hello() {
    return "Hello " + JWTRequestFilter.UserClaim;
}

当具有ADMIN 角色的用户尝试访问/hello 时,将返回403。我在 websecurity 类中启用了以下功能。

@EnableGlobalMethodSecurity(prePostEnabled = true)

下面是 JWT 令牌。

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzZW50aHVyYW4iLCJSb2xlcyI6WyJBRE1JTiIsIlVTRVIiXSwiZXhwIjoxNTkzMDE0NDE5LCJpYXQiOjE1OTI5Nzg0MTl9.-7lTav3Nux8WVafUBGXjOxtXcE-r0fpfjb7wM7hrg6w

即使 JWT 令牌具有角色,但我仍然得到 403。此预授权注释是从 JWT 中看到角色还是进行数据库调用并检查用户的角色。即使我使用了 @987654327 @ 注释,但仍然得到相同的行为。如何解决这个403。下面我附上了JWTRequestFilter类。

public class JWTRequestFilter extends OncePerRequestFilter {

    @Autowired
    private MyUserDetailService userDetailService;

    @Autowired
    private JWTUtil jwtUtil;

    public static String UserClaim = "";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        final String authorizationHeader = request.getHeader("Authorization");

        String username = null;
        String jwt = null;

        if(authorizationHeader != null && authorizationHeader.startsWith("Bearer ")){
            jwt = authorizationHeader.substring(7);
            username =  jwtUtil.extractUsername(jwt);
            UserClaim = username;
        }

        if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
            UserDetails userDetails= this.userDetailService.loadUserByUsername(username);
            if (jwtUtil.validateToken(jwt, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }

        }
        chain.doFilter(request, response);
    }

}

这就是我生成 JWT 令牌和设置角色的方式。

public String generateToken(UserDetails userDetails) {
    Map<String, Object> claims = new HashMap<>();
    Set<String> Userroles = new HashSet<>();
    User user = userRepository.findByUsername(userDetails.getUsername());
    for(Role role:user.getRoles()){
        Userroles.add(role.getName());
    }
    claims.put("Roles",Userroles.toArray());
    return createToken(claims, userDetails.getUsername());
}

【问题讨论】:

  • 您是否将您的角色 JWT 设置为您的安全上下文声明?
  • @KavithakaranKanapathippillai 我已附加 JWTRequestFilter 类
  • @YogeshPrajapati 我需要知道 preAuthorize 是检查 JWT 还是从数据库检查用户是否具有特定角色。
  • @YogeshPrajapati 我附上了我如何生成令牌的代码。
  • 试试@PreAuthorize("hasRole('ROLE_ADMIN')") 就像在这个baeldung.com/spring-security-expressions-basic

标签: spring-boot authentication spring-security jwt authorization


【解决方案1】:

识别问题的建议方法

        if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
            UserDetails userDetails= this.userDetailService.loadUserByUsername(username);
            if (jwtUtil.validateToken(jwt, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                String authorities = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining());
                System.out.println("Authorities granted : " + authorities);
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            } else {
                System.out.println("Not Valid Token);
            }

        } else {
            System.out.println("No Token);
        }

结果:令牌有效但未加载权限

Authorities granted : 

建议的解决方案 修复MyUserDetailService 以在userDetails 中加载Authorities

【讨论】:

  • 我已经替换了代码,但仍然得到 403。我已经应用了您的代码,在日志中我看到以下授权:并且没有任何价值。可能是我认为当局没有任何价值,这就是它失败的原因。请建议如何解决此问题。
  • 是的,谢谢您的建议。我在 MyUserDetailService 中添加了一个新方法 private Set getAuthority(User user) { Set authority = new HashSet(); user.getRoles().forEach(role -> { authority.add(new SimpleGrantedAuthority("ROLE_" + role.getName())); });归还当局; }。并能够完成这项工作。感谢@Kavithakaran 对此提供的帮助。
  • 我也更新了 return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(), getAuthority(user));
猜你喜欢
  • 1970-01-01
  • 2019-09-18
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
  • 2020-09-24
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多