web-dev-qa-db-ja.com

SpringSecurityでカスタムログインURLを設定するUsernamePasswordAuthenticationFilterJWT認証

JWTを使用してアプリケーションを保護するために このauth0のチュートリアル をフォローしています。

最終的に次のWebSecurity構成になりました。

@EnableWebSecurity
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class WebSecurity extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService;
    private final BCryptPasswordEncoder passwordEncoder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .and().cors()
                .and().csrf()
                .disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.POST, REGISTER_URL).permitAll()
                .antMatchers(HttpMethod.POST, LOGIN_URL).permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(new JWTAuthorizationFilter(authenticationManager()))
                .addFilter(new JWTAuthenticationFilter(authenticationManager()))
                // This disables session creation on Spring Security
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

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

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }

}

および次のJWTAuthenticationFilter:

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            ApplicationUser credentials = new ObjectMapper().readValue(request.getInputStream(), ApplicationUser.class);
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            credentials.getUsername(),
                            credentials.getPassword(),
                            new ArrayList<>()
                    )
            );
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        String token = Jwts.builder()
                .setSubject(((User) authResult.getPrincipal()).getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET.getBytes())
                .compact();
        response.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
    }
}

現時点では、アプリは/loginURLでPOSTリクエストを受け付けます。URLをたとえば/api/auth/loginに変更する方法はありますか。 URL文字列を認証フィルターに挿入しますか、それともセキュリティ構成で何らかの方法で設定しますか?

7
zenn1337

拡張しています org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter それ自体が拡張します org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter 。この最後のクラスには、これを行うことを目的としたsetFilterProcessesUrlというセッターがあります。

setFilterProcessesUrl

public voidsetFilterProcessesUrl(String filterProcessesUrl)

認証が必要かどうかを決定するURLを設定します

パラメーター:filterProcessesUrl

This はそのjavadocセクションへのリンクです

したがって、WebSecurityConfigurerAdapterでは、次のようにすることができます。

@Bean
public JWTAuthenticationFilter getJWTAuthenticationFilter() {
    final JWTAuthenticationFilter filter = new JWTAuthenticationFilter(authenticationManager());
    filter.setFilterProcessesUrl("/api/auth/login");
    return filter;
}

そして、同じクラスのconfigureメソッドで、新しいインスタンスを作成する代わりに、それを参照するだけです。

.addFilter(getJWTAuthenticationFilter())
23
jlumietu

少し改善されたのは、カスタムプロセスURLを使用してフィルターを作成し、Beanを作成せずに使用することです。これは、ここ以外では必要ないと思います。

JWTAuthenticationFilter authenticationFilter = new JWTAuthenticationFilter(authenticationManager());
authenticationFilter.setFilterProcessesUrl("/mobile/login");
....
.and()
.addFilter(authenticationFilter)
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
1
Stefano