不幸的是,我找不到向Spring Security应用程序添加无状态身份验证的方法。我使用自定义AuthenticationPovider通过覆盖方法doFilter()对AJAX请求和AjaxLoginFilter进行身份验证。在这一步上一切都很好。然后,我添加持久的RememberMe服务。再次,我的应用程序运行良好。现在,我决定通过在configure()中添加.sessionCreationPolicy(SessionCreationPolicy.STATELESS)来进行无状态身份验证。并失败。我的身份验证现在不正确。我的应用程序现在仅需要“本金”即可登录(带有任何“凭据”)。凭据不受检查。我尝试进行无状态身份验证有什么问题?我认为某些authenticate()方法不正确,或者链中的过滤顺序不正确,但是我的经验不足以解决此问题。
我的AjaxLoginFilter
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (httpRequest.getRequestURL().toString().endsWith("/login") &&
httpRequest.getMethod().matches("POST")) {
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(httpRequest.getReader().lines().collect(Collectors.joining()), User.class);
Authentication auth = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
SecurityContextHolder.getContext().setAuthentication(auth);
chain.doFilter(request, response);
} else {
chain.doFilter(request, response);
}
}
}
我的WebSecurityConfig
public static final String KEY = "posc";
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
UserService userService;
@Autowired
private AjaxAuthenticationProvider ajaxProvider;
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService);
auth
.authenticationProvider(this.ajaxProvider)
.authenticationProvider(new RememberMeAuthenticationProvider(KEY));
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/**/*.css")
.antMatchers("/**/*.js")
.antMatchers("/**/*.png")
.antMatchers("/**/*.ico")
;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login")
.permitAll()
.antMatchers("/editor.html")
.hasRole("ADMIN")
.and()
.authorizeRequests()
.antMatchers("/resources/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.permitAll()
.defaultSuccessUrl("/index.html")
.and()
.exceptionHandling().accessDeniedPage("/error.html")
.and()
.logout()
.logoutUrl("/customlogout.html")
.logoutSuccessUrl("/login.html")
.permitAll()
.and()
.rememberMe()
.rememberMeServices(rememberMeServices());
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
@Bean
public AbstractRememberMeServices rememberMeServices() {
PersistentTokenBasedRememberMeServices rememberMeServices =
new PersistentTokenBasedRememberMeServices(KEY, userService, persistentTokenRepository());
rememberMeServices.setAlwaysRemember(true);
rememberMeServices.setCookieName("remember-me-posc");
rememberMeServices.setTokenValiditySeconds(1209600);
return rememberMeServices;
}
}
和我的LoginController
private AuthenticationManager authenticationManager;
@Autowired
private RememberMeServices rememberMeServices;
@PostMapping("/login")
public ResponseEntity login(final HttpServletRequest request, final HttpServletResponse response) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
Authentication authenticationFromContext =
SecurityContextHolder.getContext().getAuthentication();
rememberMeServices.loginSuccess(request, response, authenticationFromContext);
System.out.println("My login controller");
return ResponseEntity.ok(new HashMap<>());
}
我的UserService
private final UserRepository userRepository;
private static List<User> users = new ArrayList();
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username)
.map(UserDetailsAdapter::new)
.orElseThrow(() -> new UsernameNotFoundException("Can't found username \'" + username + "\'"));
}