通过基本身份验证访问 REST 的 Angular2 抛出“预检响应具有无效的 HTTP 状态代码 401”
Posted
技术标签:
【中文标题】通过基本身份验证访问 REST 的 Angular2 抛出“预检响应具有无效的 HTTP 状态代码 401”【英文标题】:Angular2 accessing REST via Basic Auth throws "Response for preflight has invalid HTTP status code 401" 【发布时间】:2016-11-05 21:32:11 【问题描述】:我们目前正在尝试在 Angular2-App 中访问 Spring Boot 应用程序的 REST-Endpoint,但尽管 Authorization 标头在 Postman 中有效(Authorization/Basic dXNlcjp1c2Vy,对于具有密码 user 的基本测试用户),当应用程序尝试访问 REST-Endpoint 时它不起作用。 Spring-Security 的配置如下:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ApplicationSecurity extends WebSecurityConfigurerAdapter
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception
builder.inMemoryAuthentication().withUser("user").password("user").roles("USER").and().withUser("admin")
.password("admin").roles("ADMIN");
@Override
protected void configure(HttpSecurity http) throws Exception
http.authorizeRequests().anyRequest().fullyAuthenticated();
http.httpBasic();
http.csrf().disable();
Angular 应用在发出第一个请求之前会要求提供凭据,如下所示:
loginTest()
let headers: Headers = new Headers('Content-Type': 'application/json', 'Accept': 'application/json');
headers.append('Authorization', 'Basic ' + window.btoa(this._username + ':' + this._password));
console.log(headers);
return this.http.get('http://localhost:8080/', headers: headers)
.map((res:any) => res.json);
使用 localhost:8080 作为 Spring Boot 应用程序。 我们已经尝试添加 Content-Policy 标签,因为早期项目也存在类似问题,如下所示:
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' 'self';
connect-src 'self' http://localhost:3000/ http://localhost:8080/ ws://localhost:3000/; img-src 'self' data:;
style-src 'unsafe-inline' 'self'; font-src 'self'"/>
但这也没有用。 我们得到的错误:
XMLHttpRequest cannot load http://localhost:8080/. Response for preflight has invalid HTTP status code 401
当通过 Chrome 查看请求时,这是响应:
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=4659A74A950FE6C99948D8F4CB245E27; Path=/; HttpOnly
WWW-Authenticate: Basic realm="Realm"
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: accept, authorization, content-type
Access-Control-Allow-Credentials: true
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 0
Date: Mon, 04 Jul 2016 07:54:30 GMT
与这里的 PostMan 相比,我看不出 Angular2-App 有什么不同。
【问题讨论】:
【参考方案1】:我认为您的问题与 CORS 有关。 Postman 是一个 chrome 插件,因此它有权执行 CORS 请求。您的 Angular 应用程序并非如此:它受到更多限制。
看到这个问题:
how Postman send requests? ajax, same origin policy对于 Angular,您需要处理 CORS。您有一个在发送实际请求之前发送的预检请求 (OPTIONS)。我认为在您的情况下,凭据不会发送到此预检请求中,因此服务器无法对其进行身份验证并返回 401 状态代码。这会阻止执行目标请求。
我看到了两种解决方案:
使用 withCredentials 参数为 true(在 RC2 的 Angular2 中可用)
this.http.get('http://...', withCredentials: true )...
仅检查目标请求的安全性,而不检查预检请求的安全性。这是在服务器端进行的配置。
有关详细信息,请参阅这些文章:
http://restlet.com/blog/2015/12/15/understanding-and-using-cors/ http://restlet.com/blog/2016/09/27/how-to-fix-cors-problems/【讨论】:
感谢四位您的帮助,这是正确的指针。我们无法将 withCredentials 设置为使用 http,但我们能够禁用 OPTIONS-requests 的授权检查,这解决了问题(给我们另一个错误消息,但这不是这张票的问题 =))以上是关于通过基本身份验证访问 REST 的 Angular2 抛出“预检响应具有无效的 HTTP 状态代码 401”的主要内容,如果未能解决你的问题,请参考以下文章
如何从 django rest 框架访问 jwt 令牌到 Angular 前端
未提供 Angular + Django REST 身份验证凭据
Angular 2 前端 django 2 REST 框架后端用户身份验证
使用 jwt 令牌的 Django API Rest Framework 和 Angular 7 身份验证