spring-security 获取未授权错误:访问此资源需要完全身份验证

cidc1ykv  于 2022-11-11  发布在  Spring
关注(0)|答案(3)|浏览(306)

我在我的应用程序中实现了JWTSpring Security来进行身份验证。
我有3个角色:管理员、版主和用户。
例如,使用用户角色登录后,我得到了主页,但当我点击按钮进入用户空间时,我得到了:
2020-09-04 09:01:22.819错误代码10148 --- [nio-8080-exec-5] c.b.s.安全性.jwt.身份验证入口点jwt:未授权错误:访问此资源需要完全身份验证
文件webSecurityConfig.java为:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        // securedEnabled = true,
        // jsr250Enabled = true,
        prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Autowired
    private AuthEntryPointJwt unauthorizedHandler;

    @Bean
    public AuthTokenFilter authenticationJwtTokenFilter() {
        return new AuthTokenFilter();
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
            .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests().antMatchers("/api/auth/**").permitAll()
            .antMatchers("/api/test/**").permitAll()
            .anyRequest().authenticated();

        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
  • 身份验证入口点Jwt为:

@Component 公共类AuthEntryPointJwt实现了身份验证入口点{

private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);

  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response,
          AuthenticationException authException) throws IOException, ServletException {
      logger.error("Unauthorized error: {}", authException.getMessage());
      response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
  }

}

  • 身份验证令牌筛选器为:

公共类AuthTokenFilter扩展了OncePerRequestFilter { @autowired 的私有JwtUtils;

@Autowired
  private UserDetailsServiceImpl userDetailsService;

  private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);

  @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);
  }

  private String parseJwt(HttpServletRequest request) {
      String headerAuth = request.getHeader("Authorization");

      if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
          return headerAuth.substring(7, headerAuth.length());
      }

      return null;
  }

}

  • JwtUtils为:

@Component 公共类JwtUtils {私有静态最终记录器logger = LoggerFactory.getLogger(JwtUtils.class);

@Value("${bezkoder.app.jwtSecret}")
  private String jwtSecret;

  @Value("${bezkoder.app.jwtExpirationMs}")
  private int jwtExpirationMs;

  public String generateJwtToken(Authentication authentication) {

      UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();

      return Jwts.builder()
              .setSubject((userPrincipal.getUsername()))
              .setIssuedAt(new Date())
              .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
              .signWith(SignatureAlgorithm.HS512, jwtSecret)
              .compact();
  }

  public String getUserNameFromJwtToken(String token) {
      return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
  }

  public boolean validateJwtToken(String authToken) {
      try {
          Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
          return true;
      } catch (SignatureException e) {
          logger.error("Invalid JWT signature: {}", e.getMessage());
      } catch (MalformedJwtException e) {
          logger.error("Invalid JWT token: {}", e.getMessage());
      } catch (ExpiredJwtException e) {
          logger.error("JWT token is expired: {}", e.getMessage());
      } catch (UnsupportedJwtException e) {
          logger.error("JWT token is unsupported: {}", e.getMessage());
      } catch (IllegalArgumentException e) {
          logger.error("JWT claims string is empty: {}", e.getMessage());
      }

      return false;
  }

}

  • 授权控制器为:

@CrossOrigin(起源=“*",最大年龄= 3600)@RestController @请求Map(“/api/auth”)公共类授权控制器{ @自动连线认证管理器认证管理器;

@Autowired
      UserRepository userRepository;

      @Autowired
      RoleRepository roleRepository;

      @Autowired
      PasswordEncoder encoder;

      @Autowired
      JwtUtils jwtUtils;

      @PostMapping("/signin")
      public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {

          System.out.println("---------------- auth 1 ");
          Authentication authentication = authenticationManager.authenticate(
                  new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));

          SecurityContextHolder.getContext().setAuthentication(authentication);
          String jwt = jwtUtils.generateJwtToken(authentication);

          UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();      
          List<String> roles = userDetails.getAuthorities().stream()
                  .map(item -> item.getAuthority())
                  .collect(Collectors.toList());

          return ResponseEntity.ok(new JwtResponse(jwt, 
                                                   userDetails.getId(), 
                                                   userDetails.getUsername(), 
                                                   userDetails.getEmail(), 
                                                   roles));
      }

      @GetMapping("/user")
      @PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')")
      public String userAccess()
      {
          System.out.println("---------------- test User ");
          return "User Content.";
      }
  }

文件application.properties,我将其放入:

spring.datasource.url=...
spring.datasource.username=...
spring.datasource.password=...
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation= true
spring.jpa.properties.hibernate.dialect=...
spring.jpa.hibernate.ddl-auto=update
bezkoder.app.jwtSecret= bezKoderSecretKey
bezkoder.app.jwtExpirationMs= 86400000

在浏览器控制台中,我得到了that exception
你能帮我解决这个问题吗?非常感谢。

mu0hgdu0

mu0hgdu01#

您应该注解@PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')")
说说结果吧?

0mkxixxg

0mkxixxg2#

您必须根据控制器Map更新WebSecurityConfig。

.antMatchers("/**").permitAll()
      .anyRequest().authenticated();
rt4zxlrg

rt4zxlrg3#

你可能在postman或者amnesasia或者你正在使用的任何API测试工具中测试错误。如果你正在使用postman:
1.选择标题选项卡
2.单击“隐藏自动生成的标题”按钮
3.在“密钥”列下键入“Authorization”(不带引号)。
4.在“值”列下键入“不记名”,然后粘贴令牌。确保“不记名”和“令牌”之间有空格。
5.发送请求

相关问题