Я пытаюсь реализовать аутентификацию входа в систему при весенней загрузке, я использовал Spring безопасность и использовал форму реагирования во внешнем интерфейсе для аутентификации, я использую axios для вызова моего /login
, который работает хорошо, форма открывается и аутентифицируется отлично, но проблема заключается здесь заключается в том, что после успешного входа в систему я не могу получить доступ к другим конечным точкам, объявленным в моем контроллере Spring
Это моя конфигурация безопасности Spring
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth->auth
.requestMatchers("/","/login/**","/register")
.permitAll()
.anyRequest()
.authenticated())
.logout(logout->logout
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true))
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session->session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
.build();
}
Мой контроллер входа
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody RegisterUser registerUser) {
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(registerUser.getEmail(), registerUser.getPassword())
);
if (authentication.isAuthenticated()) {
return ResponseEntity.ok().body("Login successful");
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Login failed");
}
} catch (AuthenticationException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Login failed");
}
}
Это моя форма реакции
axios.defaults.baseURL = "http://localhost:8080"
axios.defaults.withCredentials=true;
const Login=()=>{
const [email, setEmail]=React.useState('');
const [password, setpassword]=React.useState('');
const [error, setError] = React.useState('');
const navigate =useNavigate();
const handlesubmit= async (e)=>{
e.preventDefault();
try {
const response = await axios.post("/login" ,{
email,
password,
});
if (response.status===200){
console.error(email,password)
navigate('/');
}
else {
navigate('/logs')
}
}
catch (e){
console.error(e)
setError("login failed")
}
}
Пробовал использовать login->login.form("/login")
и loginprocesssurl("/login")
в конфигурации безопасности, но не работает, я также установил прокси-сервер на порт, на котором работает Spring, но у меня нет результатов
Теперь я хочу, чтобы после успешного входа в систему (это так) я хочу получить доступ к другим конечным точкам, доступ к которым могут получить только прошедшие проверку подлинности пользователи.
🤔 А знаете ли вы, что...
Java активно развивается и обновляется с появлением новых версий и функциональных улучшений.
В пользовательской конечной точке отсутствует одна небольшая деталь: SecurityContext
не заполняется во время запроса/ответа на вход. Без его сохранения дальнейшие запросы будут анонимными, несмотря на успешную аутентификацию.
Предпочтительный способ — использовать логику входа в SecurityFilterChain
:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(...)
.formLogin(it -> it
.loginPage("/") // mapped to index.html, letting react handle it
.loginProcessingUrl("/login")
.successHandler((request, response, authentication) -> {
response.setStatus(HttpStatus.OK.value());
response.getWriter().print("Login successful");
})
.failureHandler((request, response, exception) -> {
response.sendError(HttpStatus.UNAUTHORIZED.value(), "Login failed");
})
)
.logout(...)
...
.build();
}
Почему это? Он добавляет дополнительный UsernamePasswordAuthenticationFilter
, который содержит логику аутентификации вашей конечной точки @PostMapping("/login")
+ , в которой хранится SecurityContext
в ThreadLocal
. Позже он сохраняется с помощью SecurityContextRepository
в другом фильтре по цепочке. (Обратите внимание: начиная с версии 6 требуется явное сохранение)
Если вы действительно хотите контролировать процесс входа в свою конечную точку (возможно, из-за некоторых побочных эффектов), сохраните контекст там:
...
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody RegisterUser registerUser) {
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(registerUser.getEmail(), registerUser.getPassword())
);
if (authentication.isAuthenticated()) {
// storing context in ThreadLocal, later will be saved in SecurityContextPersistenceFilter
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
return ResponseEntity.ok().body("Login successful");
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Login failed");
}
} catch (AuthenticationException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Login failed");
}
}
...