Есть Spring Backend App, который для аутентификации с вебмородой использует JWT. Вроде бы даже все работает, но возникла необходимость при аутентификации кроме логина/пароля использовать еще один параметр (эта часть не имеет ничего общего с самим JWT, а должна обрабатываться usernamePasswordAuthenticationFilter'ом с некоторой кастомизацией).
Идея в следующем:
1. Создаем кастомный AuthenticationDetailsSource, который будет возвращать третий параметр.
2. Валидация должна быть реализована в кастомном AbstractUserDetailsAuthenticationProvider.
3. Подвязать первые два пункта к SecurityConfig.
Вот с последним пунктом, кажется, и возникают трудности.
Кастомный AuthenticationDetailsSource
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
@Component
public class WebAuthenticationDetailsSourceImpl implements AuthenticationDetailsSource<HttpServletRequest, JwtAuthenticationRequest> {
@Override
public JwtAuthenticationRequest buildDetails(HttpServletRequest context) {
System.out.println("___#####_____");
System.out.println(context);
System.out.println("___#####_____");
return new JwtAuthenticationRequest(); // POJO
}
}
Кастомный AbstractUserDetailsAuthenticationProvider
1.
2.
3.
4.
5.
6.
7.
8.
9.
public class CustomUserDetailsAuthenticationProvider extends DaoAuthenticationProvider {
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
JwtAuthenticationRequest details = (JwtAuthenticationRequest) authentication.getDetails();
System.out.println(details); // null
// future validation
}
}
Security Config
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
@SuppressWarnings("SpringJavaAutowiringInspection")
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationDetailsSource<HttpServletRequest, ?> webAuthenticationDetailsSourceImpl;
@Autowired
private CustomUserDetailsAuthenticationProvider customAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
@Bean
public CustomUserDetailsAuthenticationProvider myAuthProvider() throws Exception {
CustomUserDetailsAuthenticationProvider provider = new CustomUserDetailsAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}
@Bean
public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter();
usernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManager());
usernamePasswordAuthenticationFilter.setAuthenticationDetailsSource(webAuthenticationDetailsSourceImpl);
return usernamePasswordAuthenticationFilter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
JwtAuthenticationTokenFilter authenticationTokenFilter = new JwtAuthenticationTokenFilter();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// allow anonymous resource requests
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js"
).permitAll()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
// disable page caching
httpSecurity.headers().cacheControl();
}
}
Собственно конфиг собран на коленке, буду благодарен за любые советы, очень хотелось бы с этим раз и навсегда разобраться :)