Spring Security 中的自定义 LoginController 并使用 Angular 发布

问题描述 投票:0回答:1

我正在尝试创建自己的 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) {}

}

错误:

错误

java angular rest http spring-restcontroller
1个回答
0
投票

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。

© www.soinside.com 2019 - 2024. All rights reserved.