Я пытаюсь включить Spring Security в проекте служб остальной загрузки, и у меня возникают некоторые проблемы.
Я настроил его с этим кодом
@Configuration
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private LdapAuthenticationProvider ldapAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic().and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(ldapAuthenticationProvider);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
и реализовалпользовательский провайдер аутентификации для входа в LDAP (который имеет нестандартную конфигурацию, поэтому я не смог заставить работать провайдера ldap по умолчанию)
@Component
public class LdapAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String email = authentication.getName();
String password = authentication.getCredentials().toString();
LdapConnection ldap = new LdapConnection();
String uid = ldap.getUserUID(email);
if(uid == null || uid == ""){
throw new BadCredentialsException("User " + email + " not found");
}
if(ldap.login(uid, password)){
return new UsernamePasswordAuthenticationToken(uid, null, new ArrayList<>());
}else{
throw new BadCredentialsException("Bad credentials");
}
}
@Override
public boolean supports(Class<?> authentication) {
return true;
//To indicate that this authenticationprovider can handle the auth request. since there's currently only one way of logging in, always return true
}
}
Этот код работает нормально, в том смысле, что вызовмои сервисы с базовым заголовком авторизации могут правильно войти в систему и вернуть вызванную услугу.Проблемы начались, когда я попытался вставить другую авторизацию / аутентификацию.Вместо использования базовой аутентификации я хотел бы передать учетные данные из формы в моем интерфейсе реагирования, поэтому я хотел бы передать их как тело json в вызове POST.(идея состоит в том, чтобы сгенерировать токен jwt и использовать его для следующего обмена данными).
Таким образом, я изменил метод настройки следующим образом:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
и определил пользовательский фильтр аутентификации:
public class JWTAuthenticationFilter extends
UsernamePasswordAuthenticationFilter {
@Autowired
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException{
String requestBody;
try{
requestBody = IOUtils.toString(req.getReader());
JsonParser jsonParser = JsonParserFactory.getJsonParser();
Map<String, Object> requestMap = jsonParser.parseMap(requestBody);
return authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(requestMap.get("email"), requestMap.get("password"), new ArrayList<>()));
}catch(IOException e){
throw new InternalAuthenticationServiceException("Something goes wrong parsing the request body",e );
}
}
@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException{
JwtTokenProvider tokenProvider = new JwtTokenProvider();
String token = tokenProvider.generateToken(auth.getPrincipal().toString());
Cookie cookie = new Cookie("jwt",token);
cookie.setHttpOnly(true);
cookie.setSecure(true);
res.addCookie(cookie);
}
}
Проблема в том, что, что бы я ни делал, среда выполнения вообще не входит в этот фильтр.Чего мне не хватает?Я предполагаю, что это что-то большое и глупое, но я не могу понять это ...
ОБНОВЛЕНИЕ: проблема заключается в том, что UsernamePassWordAuthenticationFilter может быть вызван только через форму.Затем я изменяю свой код для расширения AbstractAuthenticationProcessingFilter.
Измененный фильтр:
public class JWTAuthenticationFilter extends
AbstractAuthenticationProcessingFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
super("/api/secureLogin");
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException{
String requestBody;
try{
requestBody = IOUtils.toString(req.getReader());
JsonParser jsonParser = JsonParserFactory.getJsonParser();
Map<String, Object> requestMap = jsonParser.parseMap(requestBody);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(requestMap.get("email"), requestMap.get("password"), new ArrayList<>());
return authenticationManager.authenticate(token);
}catch(IOException e){
throw new InternalAuthenticationServiceException("Something goes wrong parsing the request body",e );
}
}
}
и измененный метод настройки:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/secureLogin").permitAll()
.antMatchers(HttpMethod.GET, "/api").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}