Spring Security 6 with Spring Boot 3 + JWT

Spring Security 6 with Spring Boot 3 + JWT

In continuation to my article Spring security 6 and spring boot 3 , Next introducing JWT token.

Learn Jwt token here .You can use jwt.io Debugger to decode, verify, and generate JWTs.

To build Spring Security 6 with Spring Boot 3 + JWT auth server , Start from jwt dependencies :

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-api</artifactId>
			<version>0.11.5</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-impl</artifactId>
			<version>0.11.5</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-jackson</artifactId>
			<version>0.11.5</version>
		</dependency>        

Next start building token end points :


    @PostMapping("/token")
    public ResponseEntity<JwtResponseDTO>  authenticateAndGetToken(
         @Valid @RequestBody AccessTokenRequest accessTokenRequestDTO,)  {
           return new ResponseEntity<>(    
                authenticationService.getAccessToken(accessTokenRequest), HttpStatus.OK);
    }

    @PostMapping("/refresh_token")
    public ResponseEntity<JwtResponseDTO> refreshtoken(
          @Valid @RequestBody    RefreshTokenRequest request,) {

    return new ResponseEntity<>(
               authenticationService.getRefreshToken(request ), HttpStatus.OK);
    }        

Now build the AuthenticationService that generates the tokens:

 @Override
    public JwtResponseDTO getAccessToken(AccessTokenRequest accessTokenRequestDTO){

        Authentication authentication = authenticationManager
                .authenticate(new UsernamePasswordAuthenticationToken(accessTokenRequest.getUsername(), accessTokenRequest.getPassword()));

return jwtClient.authenticateAndGetToken(accessTokenRequest,authentication);
    }

    @Override
    public JwtResponse getRefreshToken(RefreshTokenRequest request) {

        String refreshToken = request.getRefreshToken();
        return jwtClient.findByToken(refreshToken)
                .map(jwtClient::verifyExpiration)
                .map(TokenRefresh::getUser)
                .map(user -> jwtClient.getJwtResponseDTO(user.getUsername()))
                .orElseThrow(() -> new RefreshTokenException("error)));
    }        

JWTClient utilty handles this for AuthenticationService for generating jwt tokens

 public JwtResponse authenticateAndGetToken(AccessTokenRequest accessTokenRequest, Authentication authentication,){

        if(authentication.isAuthenticated()){
             return JwtResponse.builder()
                .accessToken(generateToken(username))
                .tokenType("Bearer")
                .refreshToken(createRefreshToken(username).getRefreshToken())
                .expiresIn(accessTokenValiditySeconds)
                .build();
        }

        logger.error("Failed to get JWT response");
        throw new AccessTokenException("error");
    }


 private String generateToken(String username){
        Map<String, Object> claims = new HashMap<>();
       //get custom claims
        claims.put(JWTCustomClaim.name.value ,"value");
        return createToken(claims, username,accessTokenValiditySeconds);
    }

 private String createToken(Map<String, Object> claims, String username , long tokenValiditySeconds) {

        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + tokenValidityMS))
                .signWith(getSignKey(), SignatureAlgorithm.RS256).compact();
    }

private Key getSignKey() {
        try  {
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(new ClassPathResource(keystoreName).getInputStream(), keystorePassword.toCharArray());
            return keyStore.getKey(keystoreAlias, keystorePassword.toCharArray());
        } catch (Exception e) {
            throw new JwtException("Failed to load keystore", e);
        }
    }

        

jwt tokens can be cached once genrated. For subsequent logins , cache is checked first .

refresh tokens are genrated and saved to db or cache as well . Users can refresh tokens to get new access token and refresh token.

JwtClient utilty refresh tokens as below :

public TokenRefresh createRefreshToken(String userName) {

        Optional<User> optionalUser = userRepository.findByUsername(userName);

        if(optionalUser.isPresent()){
            refreshTokenRepository.deleteByUser(optionalUser.get());
            TokenRefresh refreshToken = TokenRefresh
                    .builder()
                    .refreshToken(createToken(new HashMap<>() , userName 
                                              ,refreshTokenValiditySeconds))
                    .expiryDate(Instant.now().plusMillis(refreshTokenValiditySeconds*1000))
                    .user(optionalUser.get())
                    .build();
            refreshToken = refreshTokenRepository.save(refreshToken);
            return refreshToken;
        }
        logger.error("Refresh token not found");
        throw new RefreshTokenException("error");
    }        

At last , don't forget to adjust SecurityConfig and @EnableWebSecurity

@Bean
   public SecurityFilterChain securityFilterChain(HttpSecurity http, OAuthLoginSuccessHandler oAuthLoginSuccessHandler) throws Exception {

      http
              .anonymous(AbstractHttpConfigurer::disable)

              .csrf(AbstractHttpConfigurer::disable)

              .authorizeHttpRequests(requests -> requests.requestMatchers(HttpMethod.POST,"/token" ,"/refresh_token").permitAll())


              .authenticationProvider(authenticationProvider())

              .exceptionHandling(httpSecurityExceptionHandlingConfigurer -> httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.FORBIDDEN)))


              // Disable "JSESSIONID" cookies
              .sessionManagement(conf -> conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

      return http.build();
   }        

Enjoy!

要查看或添加评论,请登录

Marwa Ali的更多文章

  • Spring Security 6 with Spring Boot 3 + KeyCloak

    Spring Security 6 with Spring Boot 3 + KeyCloak

    What is KeyCloak ? KeyCloak Open Source Identity and Access Management.It provides user federation, strong…

    1 条评论
  • Spring Security 6 with Spring Boot 3

    Spring Security 6 with Spring Boot 3

    Say goodbye to Old security , Say Hi to Spring Security 6 with Spring Boot 3 . it is easier and simpler.

  • SpringBoot batch framework

    SpringBoot batch framework

    Spring Batch is a lightweight, comprehensive batch framework designed to enable the development of robust batch…

  • Dockerizing Springboot Application

    Dockerizing Springboot Application

    Docker is a powerful tool that allows developers to package their applications into containers that can be easily…

  • Kafka Event sourcing in Event Driven Architecture

    Kafka Event sourcing in Event Driven Architecture

    What is Event Sourcing ? Event Sourcing is ensuring every change to the state of an application is captured in an event…

  • Istio addons

    Istio addons

    #devops #istio #grafana #promtheus #servicemesh Please see my previous artcile at Grafana An open source monitoring…

  • Istio service mesh

    Istio service mesh

    #devops #kubernets #istio #servicemesh What is a service mesh? Developers and operators face chanllenges with a…

  • Springboot Distributed State Machine

    Springboot Distributed State Machine

    #statemachine What is a distributed state? An application may exist in a finite number of states. when something…

  • Microservices Saga Pattern with Spring State machine

    Microservices Saga Pattern with Spring State machine

    What are sagas in microservices ? A database-per-microservice model provides many benefits for microservices…

  • SpringBoot State machine

    SpringBoot State machine

    The concept of a state machine is most likely older than any reader of this reference documentation and definitely…

社区洞察

其他会员也浏览了