Spring Boot中没有包含未经授权异常的消息字段

yhived7q  于 2022-09-18  发布在  Spring
关注(0)|答案(1)|浏览(150)

我已经做了一个自定义的异常,它应该在引发时将消息发送给客户端。然而,只要错误代码是401,即未经授权,这似乎就不起作用。我尝试将状态代码更改为其他代码,但出现消息。

注意-我已经在应用程序中设置了标志server.error.include-message=always

BadCredentialsException.Java

@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
public class BadCredentialsException extends RuntimeException{
    // Runtime exception just needs this, I guess :/
    private static final long serialVersionUID = 1;

    public BadCredentialsException(String message){
        super(message);
    }

}

以下是我尝试提出这个例外的方法。

public ResponseEntity<Boolean> loginUser(String username, String password){

    // validating username
    User user = myUserRepository.findByUsername(username).
    orElseThrow(() -> new ResourceNotFoundException("No username: " + username + " found. Please enter a correct username!"));

    // validating password
    if(!new BCryptPasswordEncoder().matches(password, user.getPassword())){
        throw new BadCredentialsException("Incorrect Password. Please enter correct password to login!");
    }        

    return ResponseEntity.ok(true);
}

注意-尽管消息在终端中显示正确。只是没有出现在客户面前。

更新1-我使用permitAll()使每个人都可以访问这个特定的终结点。在Postman中,当我选择“no auth”并使用预期异常调用此终结点时,除非我提供正确的基本身份验证凭据(任何角色),否则异常不会给出消息。我完全不知道为什么会发生这种情况。

更新2-添加安全配置代码。

SecurityConfiguration.java

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().
    authorizeRequests().        
    antMatchers(HttpMethod.POST, "/api/v2/user/login/**").permitAll().
    antMatchers(HttpMethod.POST, "/api/v2/user/", "/api/v2/user", "/api/v2/user/change-role/**").hasAuthority("ROOT").
    antMatchers(HttpMethod.GET, "/api/v2/user/", "/api/v2/user").hasAuthority("ROOT").
    antMatchers(HttpMethod.POST, "/api/v1/customers/", "/api/v1/customers").hasAnyAuthority("ADMIN", "ROOT").
    antMatchers(HttpMethod.GET, "/api/v1/customers/", "/api/v1/customers").hasAnyAuthority("EMPLOYEE", "ADMIN", "ROOT").
    anyRequest().
    authenticated().
    and().
    httpBasic();
}
0mkxixxg

0mkxixxg1#

事实上,有多种方法可以做到这一点。首先,正如**@SergVasylchak**在评论中所说,您可以使用ControllerAdvice。因此,方法如下:

@ControllerAdvice
public class GlobalExceptionHandler {

 @ExceptionHandler(BadCredentialsException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
    private Message handleMessageAuth(BadCredentialsException e, HttpServletRequest request) {
        Message message = new Message();
        message.setTimestamp(getTimeStamp());
        message.setError(HttpStatus.UNAUTHORIZED.getReasonPhrase());
        message.setStatus(HttpStatus.UNAUTHORIZED.value());
        message.setMessage(e.getMessage());
        message.setPath(String.valueOf(request.getRequestURI()));
        return message;
    }
}

Message是您的定制POJO。

public class Message {
    private String timestamp;
    private int status;
    private String error;
    private String message;
    private String path;
// getters & setters
}

另一种解决方案是实现AuthenticationEntryPoint

什么是身份验证入口点?
它是由ExceptionTranslationFilter实现的接口,基本上是一个过滤器,它是Spring Security的第一个入口点。它是检查用户是否通过身份验证并登录或抛出异常(未授权)的入口点。通常,类可以像在简单应用程序中那样使用,但当在REST、JWT等中使用Spring安全时,必须对其进行扩展以提供更好的Spring Security过滤器链管理。AuthenticationEntryPoint在Spring Web Security中用于配置应用程序,使其在未经身份验证的客户端尝试访问私有资源时执行某些操作。

看看this

身份验证入口点用于发送向客户端请求凭据的HTTP响应。有时,客户端会主动包括用户名/密码等凭据来请求资源。在这些情况下,Spring Security不需要提供向客户端请求凭据的HTTP响应,因为它们已经包含在内。在其他情况下,客户端将向其无权访问的资源发出未经身份验证的请求。在本例中,使用了一种身份验证入口点的实现来向客户端请求凭据。AuthenticationEntryPoint实现可能执行到登录页面重定向,并使用WWW-AUTHENTICATE报头进行响应,等等。

例如,如果您使用JWT身份验证,则方法如下所示。

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
// if you want to return 401 status, this is enough.

// if you want to customize your response you can make it as below.
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getOutputStream().println("{ "error": "" + authException.getMessage() + "" }"); 
    }
}

现在,可以在SecurityConfig中配置身份验证入口点了。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private JwtAuthenticationEntryPoint authenticationEntryPoint;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().
   .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
   .and()
    authorizeRequests().        
    antMatchers(HttpMethod.POST, "/api/v2/user/login/**").permitAll().
    antMatchers(HttpMethod.POST, "/api/v2/user/", "/api/v2/user", "/api/v2/user/change-role/**").hasAuthority("ROOT").
    antMatchers(HttpMethod.GET, "/api/v2/user/", "/api/v2/user").hasAuthority("ROOT").
    antMatchers(HttpMethod.POST, "/api/v1/customers/", "/api/v1/customers").hasAnyAuthority("ADMIN", "ROOT").
    antMatchers(HttpMethod.GET, "/api/v1/customers/", "/api/v1/customers").hasAnyAuthority("EMPLOYEE", "ADMIN", "ROOT").
    anyRequest().
    authenticated().
    and().
    httpBasic();
}
}

相关问题