Angular 6 Basic Auth从客户端返回401

时间:2018-11-20 19:04:12

标签: java angular angular6 basic-authentication

因此,我已经寻找问题的答案已有很长时间了,并尝试了许多建议,但似乎找不到答案。

问题是,当我使用Postman检查基本身份验证是否正常时,我会收到200代码,这一切都很好,但是当我尝试使用登录组件进行身份验证时,我会立即获得代码401并说“完整要访问此资源,必须进行身份验证。”

我对Angular来说还很陌生,并且对使用Basic Auth完全陌生,所以我不知道为什么它可以与Postman一起使用,为什么不可以在应用程序中使用。

感谢您的帮助

以下是相关代码

login-component.ts:

onLogin(form: NgForm) {
    /* ... */
    let headers = new Headers();
    let userCredentials = user.userName + ":" + user.password;
    headers.append("Origin", "http://localhost:8080");
    headers.append("Authorization", "Basic " + btoa(userCredentials));

    return this.http.post('http://localhost:8080/api/users/login', headers).subscribe(
      (response) => {
        /* ... */
      },
      (error) => {
        console.log(error);
      }
    );
}

服务器端的端点:

@PostMapping(LOG_IN)
public ResponseEntity<User> login() {
    return ResponseEntity.ok().build();
}

WebSecurityConfig:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors()
                .and()
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/h2/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .httpBasic()
                .authenticationEntryPoint(getBasicAuthEntryPoint())
                .and()
            .headers()
                .frameOptions().disable()
                .and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("admin").password("1234").roles("ADMIN");
    }

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    protected void configureAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }

    @Bean
    public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
        return new CustomBasicAuthenticationEntryPoint();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

CustomBasicAuthenticationEntryPoint:

public class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void commence(final HttpServletRequest request, 
            final HttpServletResponse response, 
            final AuthenticationException authException) throws IOException, ServletException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");

        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 : " + authException.getMessage());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("MY REALM");
        super.afterPropertiesSet();
    }
}

MyUserDetailsS​​ervice:

@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private AuthenticatedUser authenticatedUser;

    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<User> oUser = userRepository.findByUserName(username);

        if (!oUser.isPresent()) {
            throw new UsernameNotFoundException(username);
        }

        User user = oUser.get();
        authenticatedUser.setUser(user);
        Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
    grantedAuthorities.add(new SimpleGrantedAuthority(user.getRole().toString()));

        return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), grantedAuthorities);
    }
}

2 个答案:

答案 0 :(得分:1)

您需要将标头作为post方法的第3个参数传递。第二个是身体

return this.http.post('http://localhost:8080/api/users/login', {}, {headers}).subscribe(
  (response) => {

如果您使用的是角度6,则实际上应该使用新的HttpClient类,而不推荐使用旧的Http

答案 1 :(得分:0)

这是因为浏览器在发送请求之前先将OPTION方法发送到服务器,然后尝试通过允许OPTION方法来更新安全配置。像这样

protected void configure(HttpSecurity http) throws Exception
{
     http
    .csrf().disable()
    .authorizeRequests()
      .antMatchers(HttpMethod.OPTIONS,"/path/to/allow").permitAll()//allow CORS option calls
      .antMatchers("/resources/**").permitAll()
      .anyRequest().authenticated()
    .and()
    .formLogin()
    .and()
    .httpBasic();
}