Home > database >  @Value for jwt secret not working properly in Spring Security
@Value for jwt secret not working properly in Spring Security

Time:12-28

I am trying to use jwt for my spring boot project and have Spring Security setup. When I use the Internal filter which is this

@Slf4j
@RequiredArgsConstructor
public class CustomAuthorizationFilter extends OncePerRequestFilter {

    private final JwtProvider jwtProvider;
    private final String tokenPrefix = "Bearer ";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        log.info("INITIALIZE | CustomAuthorizationFilter | doFilterInternal | "   request.getRequestURI());
        LocalDateTime initTime = LocalDateTime.now();

        String token = request.getHeader(AUTHORIZATION);
        if (token != null && token.startsWith(tokenPrefix)) {
            jwtProvider.verifyJwt(token);
        } else {
            filterChain.doFilter(request, response);
        }

        log.info("COMPLETE | CustomAuthorizationFilter | doFilterInternal | "  
                Duration.between(initTime, LocalDateTime.now())   " | "   request.getRequestURI());
    }
}

Problem: In my verifyJwt, it reads the secret which is declared as below as null for some reason.

@Value("${jwt.secret}")
private String secret;

And this is my verifyJwt method

    public User verifyJwt(String token) {
        log.info("INITIALIZE | JwtProvider | verifyJwt | "   token);
        LocalDateTime initTime = LocalDateTime.now();

        if (token == null || !token.startsWith(tokenPrefix)) {
            throw new UnauthorizedException();
        }
        token = token.substring(tokenPrefix.length());
        Algorithm algorithm = Algorithm.HMAC256(secret.getBytes(StandardCharsets.UTF_8));
        JWTVerifier verifier = JWT.require(algorithm).build();
        DecodedJWT decodedJWT = verifier.verify(token);
        String username = decodedJWT.getSubject();
        String[] roles = decodedJWT.getClaim("roles").asArray(String.class);

        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
        stream(roles).forEach(role -> {
            authorities.add(new SimpleGrantedAuthority(role));
        });

        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(username, null, authorities);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        log.info("COMPLETE | JwtProvider | verifyJwt | "   Duration.between(initTime, LocalDateTime.now())   " | "  
                username);
        return (User) userDetailsService.loadUserByUsername(username);
    }

The @Value is not working obviously, but it is working fine for other methods.

Anyone has a solution to fix this problem except for declaring it like this private String secret = "secret"

This is my SpringSecurityConfiguration

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtProvider jwtProvider = new JwtProvider(userDetailsService);

        http
                .csrf().disable()
                .cors()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/contact/**",
                        "/user/duplicate/**",
                        "/user/new/**",
                        "/user/login/**",
                        "/user/auth/**",
                        "/user/findId/**",
                        "/user/findPw/**/**",
                        "/swagger-ui/index.html/**")
                .permitAll()
                .antMatchers("/user", "/user/**",
                        "/profile/**")
                .authenticated()
                .and()
                .addFilterBefore(new CustomAuthorizationFilter(jwtProvider),
                        UsernamePasswordAuthenticationFilter.class);
    }
}

CodePudding user response:

Register your CustomAuthorizationFilter as a spring bean component.

@Slf4j
@RequiredArgsConstructor
@Component // <-----------------
public class CustomAuthorizationFilter extends OncePerRequestFilter {
  ....
}

Then register your custom filter to be used just before UsernamePasswordAuthenticationFilter

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

 @Autowired
 private JwtRequestFilter jwtRequestFilter;

 @Override
    protected void configure(HttpSecurity httpSecurity) {   
      // Add a filter to validate the tokens with every request
      httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);   
  }   
}

This way your filter will be invoked just in the right order and also would be registered as a spring bean so that it has access to application context where @Value will be able to function.

  • Related