i am have react js and springboot 2.5.x application, for authorization i am using jwt sping security.
i have a requirement of when application (java process) restarts need to clear the user session and force the user to login page.
for that requirement i simply taking a timestamp variable and while login adding the timestamp to the jwt payload.
when application restarts i am updating the variable so when user try to reload the page or navigates to other page this timestamp will missmatch and its working fine.
now i am trying to add a custom json field like (isValidTokenVersion:true or false) to the HttpServletResponse of jwt response but its not adding
can you help me with this
JwtTokenUtil.java
package com.demo.services.Authentication;import com.demo.model.Users;import io.jsonwebtoken.Claims;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.stereotype.Component;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.function.Function;@Componentpublic class JwtTokenUtil { private final String secret = "secret"; private final long expiration = 24 * 60 * 60 * 1000; // Token expiration in milliseconds (24 hours) private long tokenVersion = System.currentTimeMillis(); private boolean isTokenExpired = false; public String generateToken(Users userDetails) { Map<String, Object> claims = new HashMap<>(); claims.put("version", tokenVersion); //Generating Token for authentication. return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + expiration)) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } public String extractUsername(String token) { return extractClaim(token, Claims::getSubject); } public Date extractExpiration(String token) { return extractClaim(token, Claims::getExpiration); } public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) { final Claims claims = extractAllClaims(token); return claimsResolver.apply(claims); } private Claims extractAllClaims(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } private Boolean isTokenExpired(String token) { return extractExpiration(token).before(new Date()); } public Boolean validateToken(String token, UserDetails userDetails) { final String username = extractUsername(token); final long tokenVersion = extractClaim(token, claims -> claims.get("version", Long.class)); boolean validToken = false; if(username.equals(userDetails.getUsername()) && !isTokenExpired(token) && tokenVersion == this.tokenVersion){ validToken = true; isTokenExpired = false; }else{ validToken = false; if(tokenVersion != this.tokenVersion){ isTokenExpired = true; } } return validToken; } public void updateTokenVersion() { this.tokenVersion = System.currentTimeMillis(); } public boolean isTokenExpired() { return isTokenExpired; }}
AuthenticationService.java
package com.demo.services.Authentication;import com.demo.model.Users;import com.demo.repository.UsersRepository;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.json.JSONObject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletResponse;import java.util.ArrayList;import java.util.Optional;@Servicepublic class AuthenticationService implements UserDetailsService { @Autowired private UsersRepository usersRepository; @Autowired private PasswordEncoder passwordEncoder; @Autowired private JwtTokenUtil jwttUtil; private static final Logger log = LogManager.getLogger(AuthenticationService.class);public void authenticate(String username, String password, HttpServletResponse response) { try { Optional<Users> user = usersRepository.findById(username); JSONObject json = new JSONObject(); //Checking username and password. if (user.isPresent() && new BCryptPasswordEncoder().matches(password, user.get().getPassword())) { //Generating JWT token. String token = jwttUtil.generateToken(user.get()); if (token != null && !token.isEmpty()) { json.put("response", "success"); json.put("token", token); log.error("User logged in Successfully."); } else { json.put("response", "failed"); log.error("Internal Server error while validating user credentials "); } } else { json.put("response", "failed"); log.error("Invalid Credentials Passed. "); } sendResponseToReq(json.toString(), response, 200); } catch (Exception e) { log.error("Exception While Authenticating User " + e); }}private void sendResponseToReq(String result, HttpServletResponse response, int respCode) { try { response.setStatus(respCode); response.setContentLength(result.length()); response.getWriter().write(result); } catch (Exception e) { // Handle any exceptions that occurred while sending the response e.printStackTrace(); }}@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { Users user = usersRepository.findByUsername(s); return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());}public void resetTokenVersion(){ try{ jwttUtil.updateTokenVersion(); }catch (Exception e){ log.error("Unable to reset Token Version ",e); }}}
JwtFilter.java
package com.demo.services.Authentication;import org.json.JSONObject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;import org.springframework.stereotype.Component;import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@Componentpublic class JwtFilter extends OncePerRequestFilter { @Autowired private JwtTokenUtil jwtUtil; @Autowired private AuthenticationService service; @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { String authorizationHeader = httpServletRequest.getHeader("Authorization"); String token = null; String userName = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { token = authorizationHeader.substring(7); userName = jwtUtil.extractUsername(token); } if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = service.loadUserByUsername(userName); if (jwtUtil.validateToken(token, userDetails)) { UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); usernamePasswordAuthenticationToken .setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest)); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); }else if(jwtUtil.isTokenExpired()){ JSONObject json = new JSONObject(); json.put("invalidTokenVersion", true); httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); httpServletResponse.setContentType("application/json"); httpServletResponse.getWriter().write(json.toString()); } } filterChain.doFilter(httpServletRequest, httpServletResponse); }}
and also tried some more things like
httpServletResponse.setHeader("Custom-Header-Name", "Custom-Value");package com.demo.services.Authentication;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;public class MyResponseRequestWrapper extends HttpServletResponseWrapper{ public MyResponseRequestWrapper(HttpServletResponse response) { super(response); }}HttpServletResponse myResponse = (HttpServletResponse) response; MyResponseRequestWrapper responseWrapper = new MyResponseRequestWrapper(myResponse); responseWrapper.addHeader("customHeader", "customValue"); filterChain.doFilter(request, myResponse);
this is what i tried please help
thanks