In this project I just added a user entity and role entity and added jwt auth which everything works well untill the jwt expires. After adding a filter and an entry point, I got an error which is raised by the entry point:
{ "error": "Full authentication is required to access this resource" }
In the JwtRequest filter, I added a try catch to catch a ExpiredJwtException, but I'm still unable to refresh the token and getting the response of the endpoint requested.
/* Intercepts every request and examine the header for jwt */ @Component public class JwtRequestFilter extends OncePerRequestFilter { @Autowired private AuthService authService; @Autowired private RestTemplate restTemplate; @Autowired private JwtUtil jwtUtil; private static final String REFRESH_TOKEN = "http://localhost:8080/refreshtoken"; private static final String AUTHENTICATION_URL = "http://localhost:8080/authenticate"; protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { /*Get only the token */ String jwt = extractJwtFromRequest(request); if(StringUtils.hasText(jwt) && this.jwtUtil.validateToken(jwt)) { System.out.println("Entro ," +jwt); UserDetails userDetails = this.authService.refreshTokenUserDetails(this.jwtUtil.getUsernameFromToken(jwt)); UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); /* After setting the auth in the context, we specify that the current user is authenticated.. * So it passes the Spring Security Config successfully */ SecurityContextHolder.getContext().setAuthentication(authToken); } else { System.out.println("Cannot set the Security Context"); } } catch (ExpiredJwtException ex) { /* Expired token */ if (ex.getMessage().contains("io.jsonwebtoken.ExpiredJwtException")) { request.setAttribute("claims", ex.getClaims()); /* Refresh token*/ String jwt = this.refreshToken(extractJwtFromRequest(request)); request.setAttribute("Autorization", jwt); Object[] res = this.getData(request, jwt); byte[] body = new ObjectMapper().writeValueAsBytes(res); response.getOutputStream().write(body); } } catch (BadCredentialsException ex) { request.setAttribute("exception", ex); throw ex; } catch (Exception e) { System.out.println(e); throw e; } filterChain.doFilter(request, response); } private String getData(HttpServletRequest request, String token) { String response = null; HttpHeaders headers = getHeaders(); headers.set("Authorization", token); headers.set("isRefreshToken", "true"); HttpEntity<String> jwtEntity = new HttpEntity<String>(headers); /* Use token to get response */ String urlRequested = request.getRequestURL().toString(); ResponseEntity<String> requested = restTemplate.exchange(urlRequested, HttpMethod.GET, jwtEntity, String.class); if(requested.getStatusCode().equals(HttpStatus.OK)) { response = requested.getBody(); } return response; } private HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.set("Content-Type", MediaType.APPLICATION_JSON_VALUE); headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); return headers; } private String extractJwtFromRequest(HttpServletRequest request) { String authorizationHeader = request.getHeader("Authorization"); if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { return authorizationHeader.substring(7); } return null; } private String refreshToken(String token) { HttpHeaders headers = getHeaders(); headers.set("Authorization", token); headers.set("isRefreshToken", "true"); HttpEntity<String> jwtEntity = new HttpEntity<String>(headers); /* Use Token to get Response */ ResponseEntity<AuthResponse> refreshTokenResponse = restTemplate.exchange(REFRESH_TOKEN, HttpMethod.GET, jwtEntity, AuthResponse.class); if(refreshTokenResponse.getStatusCode().equals(HttpStatus.OK)) { return "Bearer " + refreshTokenResponse.getBody().getJwt(); } return null; } private void allowForRefreshToken(ExpiredJwtException ex, HttpServletRequest request) { /* Create a UsernameAuthenticationToken with null values */ UsernamePasswordAuthenticationToken upat = new UsernamePasswordAuthenticationToken(null, null, null); /* After setting the auth in the context, we specify that the current user is authenticated. So it * passes the Spring Security Config successfully */ SecurityContextHolder.getContext().setAuthentication(upat); /* Set the claims so that in controller we will be using it to create new Jwt */ request.setAttribute("claims", ex.getClaims()); } }
JwtAuthenticationEntryPoint
@Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType(MediaType.APPLICATION_JSON_VALUE); String message; /* Check if the request as any exception that we have stored in Request */ final Exception exception = (Exception) request.getAttribute("exception"); // If yes then use it to create the response message else use the authException if (exception != null) { byte[] body = new ObjectMapper().writeValueAsBytes(Collections.singletonMap("cause", exception.toString())); response.getOutputStream().write(body); } else { if (authException.getCause() != null) { message = authException.getCause().toString() + " " + authException.getMessage(); } else { message = authException.getMessage(); } /* Error on postman */ byte[] body = new ObjectMapper().writeValueAsBytes(Collections.singletonMap("error", message)); response.getOutputStream().write(body); } } }
SessionController endpoint
@RequestMapping(value = "/refresh-token", method = RequestMethod.GET) public ResponseEntity<?> refreshToekn(HttpServletRequest request) throws Exception { /* From the http ruest get claims */ DefaultClaims claims = (io.jsonwebtoken.impl.DefaultClaims) request.getAttribute("claims"); Map<String, Object> expectedMap = this.authService.getMapFromIoJsonwebtokenClaims(claims); String token = this.authService.refreshToken(expectedMap, expectedMap.get("sub").toString()); return ResponseEntity.ok(new AuthResponse(token)); }
AuthService
public String refreshToken(Map<String, Object> claims, String subject) { return this.jwtUtil.createTokenInfinity(claims, subject); } public Map<String, Object> getMapFromIoJsonwebtokenClaims(Claims claims) { Map<String, Object> expectedMap = new HashMap<String, Object>(); for (Map.Entry<String, Object> entry : claims.entrySet()) { expectedMap.put(entry.getKey(), entry.getValue()); } return expectedMap; }
And finally JwtUtil
public String createTokenInfinity(Map<String, Object> claims, String subject) { /* Subject -> person who has been authenticated */ return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + REFRESH_TIME)) //* 60 *60 *800) .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact(); }
If you can tell me a better approach to get this done, I'll be very helpful.
https://stackoverflow.com/questions/66947472/unable-to-set-refresh-token-and-get-back-the-response April 05, 2021 at 10:01AM
没有评论:
发表评论