Я реализовал решение для аутентификации с помощью токена JWT при весенней загрузке после этого https://www.djamware.com/post/5c819d0180aca754f7a9d1ee/securing-restful-api-with-spring-boot-security-and-data-mongodb, которое отлично работает, за исключением двух вещей, оно не перенаправляет на страницу, с которой был сделан запрос, перед перенаправлением на страницу входа и SuccessHandler не работает. Из проведенных тестов мне кажется, что проблема в том, что нет успешной аутентификации, но я не знаю, как ее решить. Код следующий
securityconfig
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
JwtTokenProvider jwtTokenProvider;
@Autowired
CustomAuthenticationSuccessHandler authenticationSuccess;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
UserDetailsService userDetailsService = mongoUserDetails();
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests()
.antMatchers("/", "/search_posts", "/wall/**", "/resources/**", "/css/**", "/js/**", "/webjars/**", "/api/auth/login").permitAll()
.antMatchers("/exams/**").hasAuthority(Role.STUDENT.toString())
.anyRequest().authenticated()
.and().formLogin().loginPage("/login").permitAll()
.successHandler(authenticationSuccess)
.and().csrf().disable();
// Apply JWT
http.apply(new JwtConfigurer(jwtTokenProvider));
//filtro para poner JWT en la cabecera del request
http.addFilterBefore(new RequestWrapperFilter(), UsernamePasswordAuthenticationFilter.class);
//http.addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
http.httpBasic().disable();
//.apply(new JwtConfigurer(jwtTokenProvider));
}//.and()//.exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint())
@Bean
public PasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public AuthenticationEntryPoint unauthorizedEntryPoint() {
return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"Unauthorized");
}
@Bean
public UserDetailsService mongoUserDetails() {
return new CustomUserDetailsService();
}
}
jwttoken filter
public class JwtTokenFilter extends GenericFilterBean {
private JwtTokenProvider jwtTokenProvider;
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
throws IOException, ServletException {
String token = jwtTokenProvider.resolveToken((HttpServletRequest) req);
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication auth = token != null ? jwtTokenProvider.getAuthentication(token) : null;
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(auth);
}
filterChain.doFilter(req, res);
}
}
jwttoken provider
@Component
public class JwtTokenProvider {
@Value("${security.jwt.token.secret-key:secret}")
private String secretKey = Constants.SECRET;
@Value("${security.jwt.token.expire-length:3600000}")
private long validityInMilliseconds = 10800000; // 3h
@Autowired
private CustomUserDetailsService userDetailsService;
@PostConstruct
protected void init() {
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
}
public String createToken(String username, Set<Role> roles) {
Claims claims = Jwts.claims().setSubject(username);
claims.put("roles", roles);
Date now = new Date();
Date validity = new Date(now.getTime() + validityInMilliseconds);
return Jwts.builder()//
.setClaims(claims)//
.setIssuedAt(now)//
.setExpiration(validity)//
.signWith(SignatureAlgorithm.HS256, secretKey)//
.compact();
}
public Authentication getAuthentication(String token) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(getUsername(token));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
public String getUsername(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
}
public String resolveToken(HttpServletRequest req) {
String bearerToken = req.getHeader(Constants.AUTHORIZATION);
if (bearerToken != null && bearerToken.startsWith(Constants.BEARER)) {
return bearerToken.substring(Constants.BEARER.length(), bearerToken.length());
}
return null;
}
public boolean validateToken(String token) {
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
if (claims.getBody().getExpiration().before(new Date())) {
return false;
}
return true;
} catch (JwtException | IllegalArgumentException e) {
throw new JwtException("Expired or invalid JWT token");
}
}
}
фильтр
public class JwtConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private JwtTokenProvider jwtTokenProvider;
public JwtConfigurer(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
public void configure(HttpSecurity http) throws Exception {
JwtTokenFilter customFilter = new JwtTokenFilter(jwtTokenProvider);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
the apirest
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
JwtTokenProvider jwtTokenProvider;
@Autowired
UserRepository users;
@Autowired
private CustomUserDetailsService userService;
@Autowired
AuthenticationSuccessHandler ash;
@PostMapping("/login")
public void login(@ModelAttribute("user") Users user, HttpServletRequest req, HttpServletResponse response) throws IOException, ServletException {
try {
//set authentication
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(auth);
//create a token
String token = jwtTokenProvider.createToken(user.getUsername(), this.users.findByUsername(user.getUsername()).getRoles());
//create and set a cookie
Cookie cookie = new Cookie(Constants.TOKEN, token);
cookie.setMaxAge(3 * 60 * 60); // expires in 3 hours
cookie.setHttpOnly(true);
cookie.setPath("/");
//add cookie to response
response.addCookie(cookie);
//call to onauthenticationsuccess
//ash.onAuthenticationSuccess(req, response, auth);
}
catch (AuthenticationException e) {
throw new BadCredentialsException("Invalid email/password supplied");
}
}
Пожалуйста, я немного растерялся и не могу найти решение проблемы, правда ли, что Spring перенаправляет вас на запрашиваемую страницу перед страницей входа ? Есть ли способ перенаправить на предыдущую страницу перед входом в систему? спасибо