我有一个 spirngboot 应用程序,我使用 JWT 来保证安全性,所以我在服务中有这段代码
public void registrarUsuario(RegisterDTO registerDTO){
if (authRepository.existsByEmail(registerDTO.getEmail())){
throw new UserAlreadyRegisterException();
}
Usuarios usuario = new Usuarios();
usuario.setPrimer_nombre(registerDTO.getPrimer_nombre());
usuario.setSegundo_nombre(registerDTO.getSegundo_nombre());
usuario.setPrimer_apellido(registerDTO.getPrimer_apellido());
usuario.setSegundo_apellido(registerDTO.getSegundo_apellido());
usuario.setEmail(registerDTO.getEmail());
usuario.setTelefono(registerDTO.getTelefono());
Credenciales credencial = new Credenciales();
credencial.setContraseña(passwordEncoder.encode(registerDTO.getContraseña()));
credencialesRepository.save(credencial);
usuario.setCredenciales(credencial);
Roles roles = rolRepository.findByNombre("usuario").orElseThrow(() -> new NoSuchElementException("No se encontro el rol usuarios"));
usuario.setRoles(Collections.singletonList(roles));
authRepository.save(usuario);
}
当我尝试注册新用户时,如果该用户已经存在,我将创建异常 UserAlready... 并在响应中显示正确的格式
{
"timeStamp": "2024-09-27T04:07:37.495+00:00",
"code": "p-500",
"message": "El usuario ya se encuentra registrado en la aplicacion",
"url": "/api/v1/auth/register"
}
但是,当我尝试在另一个端点中的令牌过期时创建异常时,我的全局处理不会捕获此异常,它仅显示在我的控制台中。
这是我的代码
我的异常处理程序:
package com.api.reservavuelos.Exceptions;
import com.api.reservavuelos.DTO.ResponseExceptionDTO;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Date;
@RestControllerAdvice
public class GlobalExceptionHandler {
private Date tiempoactual = new Date();
@ExceptionHandler(JwtTokenExpiredException.class)
public ResponseEntity<ResponseExceptionDTO> handleJwtTokenExpiredException(HttpServletRequest request, JwtTokenExpiredException exception){
return new ResponseEntity<>(new ResponseExceptionDTO(tiempoactual,"P-401", exception.getMessage(), request.getRequestURI()), HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(AuthenticationCredentialsNotFoundException.class)
public ResponseEntity<ResponseExceptionDTO> handleAuthenticationCredentialsNotFoundException(HttpServletRequest request , AuthenticationCredentialsNotFoundException exception){
return new ResponseEntity<>(new ResponseExceptionDTO(tiempoactual,"P-401", exception.getMessage(), request.getRequestURI()), HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ResponseExceptionDTO> handleUserNotFoundException(HttpServletRequest request, UserNotFoundException exception) {
return new ResponseEntity<>(new ResponseExceptionDTO(tiempoactual,"P-404", exception.getMessage(), request.getRequestURI()), HttpStatus.NOT_FOUND);
}
@ExceptionHandler(UserAlreadyRegisterException.class)
public ResponseEntity<ResponseExceptionDTO> handleUserAlreadyRegisterException(HttpServletRequest request, UserAlreadyRegisterException exception) {
return new ResponseEntity<>(new ResponseExceptionDTO(tiempoactual,"p-500", exception.getMessage(), request.getRequestURI()), HttpStatus.BAD_REQUEST);
}
}
我的 JwtTokenProvider
package com.api.reservavuelos.Security;
import com.api.reservavuelos.Exceptions.JwtTokenExpiredException;
import com.api.reservavuelos.Exceptions.UserAlreadyRegisterException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtTokenProvider {
public String generateToken(Authentication authentication) {
// Implementación JWT Token generación
String username = authentication.getName();
Date tiempoactual = new Date();
Date expiracion = new Date(tiempoactual.getTime() + ConstantSecurity.JWT_EXPIRATION_TOKEN);
String Token = Jwts.builder()
.setSubject(username)
.setIssuedAt(tiempoactual)
.setExpiration(expiracion)
.signWith(SignatureAlgorithm.HS512, ConstantSecurity.JWT_FIRMA)
.compact();
return Token;
}
public String getUsernameFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(ConstantSecurity.JWT_FIRMA)
.build()
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
}
public Boolean IsValidToken(String token) {
try {
Jwts.parser()
.setSigningKey(ConstantSecurity.JWT_FIRMA)
.build()
.parseClaimsJws(token);
return true;
}catch (ExpiredJwtException e) {
throw new JwtTokenExpiredException("Jwt ha expirado");
} catch (AuthenticationCredentialsNotFoundException e) {
throw new AuthenticationCredentialsNotFoundException("Jwt esta incorrecto");
}
}
}
我不确定您的安全过滤器是如何配置的,但我的经验是,在 MVC 接管并且
ControllerAdvice
出现之前调用调用 JWT 处理的安全过滤器。
我的解决方案(但我有一个自定义安全过滤器)是在过滤器中捕获 JWT 异常,并将带有错误消息的 401 直接写入响应中。比如:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
// Process JWT and pass execute on if JWT is valid
} catch (JwtException e) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
objectMapper.writeValue(response.getOutputStream(),
ErrorInfo.createWithMessage(e.getMessage(), request.getRequestURI()));
}
}