Hello everyone
In the previous part, I talked about my experiences with updating to Spring 3.x. (https://medium.com/@lastjavabuilder/step-by-step-migration-to-spring-3-x-jakarta-security-hibernate-6-openapi-cache-925401fa7b2c)
In this article, I will share my experiences with the configurations that were updated and deprecated with Spring Security 6.2.x while updating the project with Spring boot 3.2.x.
Lets start :)
While I updated the Spring Boot project to 3.2.4, I also updated the spring security-related dependencies to 6.2.3. I also updated the jsonwebtoken related dependencies (jjwt-api, jjwt-impl, jjwt-jackson) to version 0.12.5.
When I maven update-clean-installed the project, many methods were deprecated and error on both the spring security side and the JWT lib side.
In this article, I will share code blocks on how I solved these problems.
- Let’s start by updating the project to spring boot 3.2.4.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.4</version>
<relativePath/>
</parent>
2. Let’s update the dependencies related to spring security to 6.2.3, either externally or with the security library of spring boot.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- or external definitation -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>6.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>6.2.3</version>
</dependency>
<!-- etc definitation -->
3. Let’s update the version of jjwt-api, jjwt-impl, jjwt-jackson dependencies of the io.jsonwebtoken library to 0.12.5.
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
When you do a maven update on the project, you will first see that there is an error in the libraries belonging to jsonwebtoken. Let’s start by solving this first.
- create token with Jwts (example)
Old definition
Jwts
.builder()
.setClaims(extraClaims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(new Date(System.currentTimeMillis() + 1000 * 60 * 24)))
.signWith(yourKey, SignatureAlgorithm.HS256) // SignatureAlgorithm.HS256 or etc SignatureAlgorithm enum
.compact();
New definition
Jwts
.builder()
.claims(extraClaims)
.subject(userDetails.getUsername())
.issuedAt(new Date(System.currentTimeMillis()))
.expiration(new Date(System.currentTimeMillis() + 1000 * 60 * 24))
.signWith(yourPrivateKey)
.compact();
- get Claims (example)
Old definition
Jwts
.parserBuilder()
.setSigningKey(yourKey)
.build()
.parseClaimsJws(yourToken)
.getBody();
New definition
Jwts
.parser()
.verifyWith(yourSecretKey)
.build()
.parseSignedClaims(yourToken)
.getPayload();
- get userId from token (example)
Old definition
Claims claims = Jwts
.parserBuilder()
.setSigningKey(yourPublicKey)
.build()
.parseClaimsJws(yourToken)
.getBody();
Long userId = Long.parseLong(claims.getSubject());
New definition
Claims claims = Jwts
.parser()
.verifyWith(yourPublicKey)
.build()
.parseSignedClaims(yourToken)
.getPayload();
Long userId = Long.parseLong(claimsJws.getSubject());
- validate token (example)
Old definition
Jwts
.parserBuilder()
.setSigningKey(yourPublicKey)
.build()
.parseClaimsJws(yourToken);
New definition
Jwts
.parser()
.verifyWith(yourPublicKey)
.build()
.parseSignedClaims(yourToken);
After solving the jsonwebtoken side, the main point is to configure spring security.After updating to Spring security version 6.2.x, you will see that many methods are deprecated.
Let’s start solving this situation
Old definition (example)
private static final String[] AUTH_WHITELIST = {
"/v3/api-docs/**",
"/swagger-resources/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/actuator/**",
"/login",
"/logout",
"/auth/**",
"/oauth2/**",
"/error",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js"
};
@Bean
public SecurityFilterChain filterChain( HttpSecurity http) throws Exception {
http.
cors().configurationSource(yourCorsConfiguration())
.and()
.headers().xssProtection().disable().and()
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.formLogin().disable()
.httpBasic().disable()
.exceptionHandling()
.authenticationEntryPoint(yourAuthenticationEntryPoint())
.and()
.authorizeHttpRequests(auth -> auth
.requestMatchers(AUTH_WHITELIST)
.permitAll()
.anyRequest()
.authenticated())
.oauth2Login()
.clientRegistrationRepository(yourClientRegistrationRepository())
.authorizationEndpoint()
.authorizationRequestResolver(yourAuthorizationRequestResolver())
.baseUri("yourBaseUri")
.authorizationRequestRepository(yourAuthorizationRequestRepository())
.and()
.redirectionEndpoint()
.baseUri("yourRedirectBaseUri")
.and()
.tokenEndpoint()
.accessTokenResponseClient(yourAccessTokenResponseClient())
.and()
.userInfoEndpoint()
.userService(yourUserService())
.and()
.successHandler(yourAuthSuccessHandler)
.failureHandler(yourAuthFailureHandler)
.and()
.logout()
.disable()
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(yourJwtAuthConverter)
.and()
.and()
.addFilterBefore(yourJwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
New definition
private static final String[] AUTH_WHITELIST = {
"/v3/api-docs/**",
"/swagger-resources/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/actuator/**",
"/jwtcheck",
"/login",
"/logout",
"/auth/**",
"/oauth2/**",
"/error",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js"
};
@Bean
public SecurityFilterChain filterChain( HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.cors(httpSecurityCorsConfigurer -> httpSecurityCorsConfigurer.configurationSource(yourCorsConfiguration()))
.headers(httpSecurityHeadersConfigurer -> httpSecurityHeadersConfigurer.xssProtection(xXssConfig -> xXssConfig.disable()))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.formLogin(httpSecurityFormLoginConfigurer -> httpSecurityFormLoginConfigurer.disable())
.httpBasic(httpSecurityHttpBasicConfigurer -> httpSecurityHttpBasicConfigurer.disable())
.exceptionHandling((exception) -> exception.authenticationEntryPoint(yourAuthenticationEntryPoint))
.authorizeHttpRequests(
authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry
.requestMatchers(AUTH_WHITELIST)
.permitAll().anyRequest().authenticated())
.oauth2Login(httpSecurityOAuth2LoginConfigurer ->
httpSecurityOAuth2LoginConfigurer
.clientRegistrationRepository(yourClientRegistrationRepository())
.authorizationEndpoint(authorizationEndpointConfig ->
authorizationEndpointConfig
.authorizationRequestResolver(yourAuthorizationRequestResolver())
.baseUri("yourBaseUri")
.authorizationRequestRepository(yourAuthorizationRequestRepository()))
.redirectionEndpoint(redirectionEndpointConfig -> redirectionEndpointConfig.baseUri("yourRedirectBaseUri"))
.tokenEndpoint(tokenEndpointConfig -> tokenEndpointConfig.accessTokenResponseClient(yourAccessTokenResponseClient()))
.userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig.userService(yourUserService()))
.successHandler(yourAuthSuccessHandler)
.failureHandler(yourAuthFailureHandler)
)
.logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer.disable())
.oauth2ResourceServer(httpSecurityOAuth2ResourceServerConfigurer ->
httpSecurityOAuth2ResourceServerConfigurer.jwt(jwtConfigurer ->
jwtConfigurer.jwtAuthenticationConverter(yourJwtAuthConverter())))
.addFilterBefore(yourJwtAuthFilter,UsernamePasswordAuthenticationFilter.class);
return http.build();
}
The .and() definitions between config elements in the old configuration have been removed. It has been replaced with lambda expressions.
Frankly, it was difficult at first for those who were used to the old structure, but switching between config structures with .and() was also more complicated.
Thank you for reading.