我正在尝试创建自己的 LoginController,以便我可以更仔细地观察数据流,但要么是我的 post 方法错误,要么是我的控制器缺少某些内容。
每当我尝试发送登录请求时,它都会跳过我的 LoginController 并直接转到 UserDetailsService 实现为空白字符串,或者我得到原始密码不能为空。
代码:
@CrossOrigin(origins = "http://localhost:4200/")
@RequiredArgsConstructor
@RestController
@RequestMapping("/login")
public class LoginController {
private final MyUserDetailsService userDetailsService;a
private final UserService userService;
private final PasswordEncoderConfig passwordEncoder;
@PostMapping
public ResponseEntity<UserDTO> loginUser(@RequestBody LoginDTO request){
String unhashedPassword = request.getPassword();
String hashedPassword = passwordEncoder.passwordEncoder().encode(unhashedPassword);
String username = request.getUsername();
Optional<UserDTO> possibleUser = userService.getUserByNickNameAndPassword(username,hashedPassword);
if (possibleUser.isPresent()) {
return ResponseEntity.ok(possibleUser.get());
} else {
return ResponseEntity.notFound().build();
}
}
}
@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class SecurityConfiguration {
private final MyUserDetailsService userDetailsService;
private final PasswordEncoder passwordEncoder;
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET","POST", "PUT", "DELETE, OPTIONS, PATCH"));
configuration.setAllowCredentials(true);
configuration.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public SecurityFilterChain securityFilterChainConfig(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors(corsConfigurationSource ->
corsConfigurationSource.configurationSource(corsConfigurationSource()))
.authorizeRequests(request ->
request
.requestMatchers("/users/all").permitAll()
.requestMatchers("/beers/propose").hasRole("USER")
.requestMatchers("/beer-updates/**").permitAll()
.requestMatchers("/topic/beer-updates/**").permitAll()
.requestMatchers("/beers/**").permitAll()
.requestMatchers("/register").permitAll()
.requestMatchers("/login").permitAll()
.anyRequest().authenticated())
.formLogin(login -> {
login.loginProcessingUrl("/login");
login.successForwardUrl("/beers/all");
login.failureUrl("/login");
});
return http.build();
}
}
@RequiredArgsConstructor
@Service
public class MyUserDetailsService implements UserDetailsService {
private final UserService userService;
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
Optional<UserDTO> userDTO = userService.getUserByNickName(username);
if(userDTO.isPresent()) {
UserDTO foundUser = userDTO.get();
return org.springframework.security.core.userdetails.User
.withUsername(foundUser .getNickName())
.password(foundUser .getPasswordHash())
.roles((foundUser .getRole()))
.build();
}
throw new NoSuchElementException("nie ma takiego uzytkownika");
}
}
@Component({
selector: 'app-login',
standalone: true,
imports: [
FormsModule
],
templateUrl: './login.component.html',
styleUrl: './login.component.css'
})
export class LoginComponent {
username : string = ''
password :string = ''
loginURL = "http://localhost:8082/login";
login() {
const body = {nickName: this.username, unhashedPassword: this.password}
this.http.post(this.loginURL, body).subscribe({
next: login => {
console.log("login successfuly ", login);
},
error: error => {
console.error("login error ", error);
},
complete: () => {
console.log("login completed");
}
})
}
constructor(private http: HttpClient) {}
}
错误:
Spring Security 的表单登录需要 CSRF,在文档中提到。
确保在处理表单登录时使用
CSRF
,因此不要在专用SecurityFilterChain
中禁用它:
@Bean
public SecurityFilterChain securityFilterChainConfig(HttpSecurity http) throws Exception {
http
// .csrf().disable() // <-- DON'T DISABLE !!!
.cors(corsConfigurationSource ->
corsConfigurationSource.configurationSource(corsConfigurationSource()))
.authorizeRequests(request ->
request
.requestMatchers("/users/all").permitAll()
.requestMatchers("/beers/propose").hasRole("USER")
.requestMatchers("/beer-updates/**").permitAll()
.requestMatchers("/topic/beer-updates/**").permitAll()
.requestMatchers("/beers/**").permitAll()
.requestMatchers("/register").permitAll()
.requestMatchers("/login").permitAll()
.anyRequest().authenticated())
.formLogin(login -> {
login.loginProcessingUrl("/login");
login.successForwardUrl("/beers/all");
login.failureUrl("/login");
});
return http.build();
}
另一种方法是使用 REST API 和 JWT。