因此,我已经寻找问题的答案已有很长时间了,并尝试了许多建议,但似乎找不到答案。
问题是,当我使用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();
}
}
MyUserDetailsService:
@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);
}
}
答案 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();
}