Внес много правок. Раньше не устанавливал контекст Springsecurity. Это ошибка, которую я получаю:
2024-07-05T02:37:01.443-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] estMatcherDelegatingAuthorizationManager : Checking authorization on POST /login_success using AuthorityAuthorizationManager[authorities=[USER]]
2024-07-05T02:37:01.443-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] w.c.HttpSessionSecurityContextRepository : Did not find SecurityContext in HttpSession 78D83992116FD8443A13A27376BEA891 using the SPRING_SECURITY_CONTEXT session attribute
2024-07-05T02:37:01.444-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2024-07-05T02:37:01.444-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2024-07-05T02:37:01.444-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=78D83992116FD8443A13A27376BEA891], Granted Authorities=[ROLE_ANONYMOUS]]
2024-07-05T02:37:01.444-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] o.s.s.w.a.ExceptionTranslationFilter : Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=78D83992116FD8443A13A27376BEA891], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied
org.springframework.security.access.AccessDeniedException: Access Denied
Это мои данные пользователя через CustomUserDetails.
public class CustomUserDetails implements UserDetails {
private User user;
private int id;
private String username;
Role user_role;
private String email;
@JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
public CustomUserDetails(User user) {
}
public CustomUserDetails(int id, String getusername, String role, String password, String email, List<GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.email = email;
this.user_role = Role.valueOf("USER");
this.password = password;
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(user.getRoles().toString());
return Arrays.asList(authority);
}
public String getPassword() {
return user.getPassword();
}
public String getUsername() {
return user.getusername();
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
return true;
}
Это мой CustomUserDetailsService.
@Service
public class CustomUserDetailsService implements UserDetailsService {
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found with username: " + username);
}
return new org.springframework.security.core.userdetails.User(user.getusername(), user.getPassword(), getAuthorities(user));
}
private Collection<? extends GrantedAuthority> getAuthorities(User user) {
List<GrantedAuthority> authorities = new ArrayList<>();
// Example: Fetching user roles and converting them to GrantedAuthority
user.getRoles().forEach(role -> {
authorities.add(new SimpleGrantedAuthority("USER"));
});
return authorities;
}
This is my loginController. I'm trying to implement securityContext.
@Контроллер публичный класс loginController {
private final AuthenticationManager authenticationManager;
private final SecurityContextHolderStrategy securityContextHolderStrategy =
SecurityContextHolder.getContextHolderStrategy();
private final SecurityContextRepository securityContextRepository =
new HttpSessionSecurityContextRepository();
private HttpServletRequest request;
private HttpServletResponse response;
PasswordEncoder bcrypt = new BCryptPasswordEncoder();
UserRepository userRepository;
public loginController(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@RequestMapping("/login")
public String login(Model model) {
return "login";
}
@PostMapping("/login_success")
public String processLogin(@RequestParam String username, @RequestParam String password,
HttpServletRequest request, HttpServletResponse response) {
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("USER");
User user = new User();
user.setusername(username);
userRepository.findByUsername(username);
user.setPassword(password);
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.authenticated(
username, password, authorities);
authenticationManager.authenticate(token);
SecurityContext securityContext = this.securityContextHolderStrategy.createEmptyContext();
securityContext.setAuthentication(token);
this.securityContextHolderStrategy.setContext(securityContext);
this.securityContextRepository.saveContext(securityContext, request, response);
return "redirect:/login_success";
}
И вот моя конфигурация безопасности:
@EnableWebSecurity // have to add or it can't find HttpSecurity type
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(Customizer.withDefaults())
.authorizeHttpRequests((requests) -> requests
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
.requestMatchers("/", "/home", "/confirmation").permitAll()
.requestMatchers("/signup").permitAll()
.requestMatchers("/login").permitAll()
.requestMatchers("/css/**").permitAll()
.requestMatchers("/login_success").hasAuthority("USER").anyRequest().authenticated()
)
.securityContext((securityContext) -> securityContext
.requireExplicitSave(true)
)
.formLogin(form ->
form
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/login_success")
.permitAll()
)
.logout(l -> l
.logoutSuccessUrl("/").permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(UserDetailsService customUserDetailsService,
PasswordEncoder encoder) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(customUserDetailsService);
authenticationProvider.setPasswordEncoder(encoder);
return new ProviderManager(authenticationProvider);
}
Лучше ли реализовать держателя контекста безопасности в конфигурации безопасности?
Следую этим документам и, похоже, не могу найти руководства по использованию пользовательской точки входа в систему для весны 6.1+.
https://docs.spring.io/spring-security/reference/6.1/migration/servlet/session-management.html
пожалуйста, не публикуйте код в комментариях, если вы видите, что он нечитаем, используйте кнопку редактирования в своем вопросе. Кроме того, всегда добавляйте обновленные журналы отладки/трассировки при каждом обновлении.
ваши конструкторы в классе CustomUserDetails кажутся неверными. Вы принимаете значения в параметризованном конструкторе, но тело пусто, которое вы также вызываете из функции сборки, а ваш непараметризованный конструктор устанавливает значения, но не имеет никаких параметров, поэтому они задаются сами.
исправьте их так:
public CustomUserDetails( ) {
}
public CustomUserDetails(int id, String getusername, String role, String password, String email, List<GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.email = email;
this.role = role;
this.password = password;
this.authorities = authorities;
}
Я внес изменения в конфигурацию входа в систему
public class loginController {
@GetMapping("/login")
public String login() {
return "login";
}
}
и конфигурация безопасности
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests((requests) -> requests
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
.requestMatchers("/", "/home", "/confirmation").permitAll()
.requestMatchers("/signup").permitAll()
.requestMatchers("/login").permitAll()
.requestMatchers("/css/**").permitAll()
.requestMatchers("/profile").permitAll()
)
.formLogin(form->
form
.loginPage("/login")
.loginProcessingUrl("/processlogin")
.defaultSuccessUrl("/profile")
.permitAll()
)
.logout(l -> l
.logoutSuccessUrl("/logout").invalidateHttpSession(true)
Работает сейчас.
После аутентификации (поскольку вы решили написать собственную конечную точку входа) вам необходимо сохранить объект аутентификации в SecurityContext. Это описано в главе «Архитектура аутентификации».