Angular JWT Auth - 总是 401 未经授权

Posted

技术标签:

【中文标题】Angular JWT Auth - 总是 401 未经授权【英文标题】:Angular JWT Auth - always 401 unauthorized 【发布时间】:2018-04-08 20:10:01 【问题描述】:

我正在创建一个简单的 cakephp 后端。对于前端,我使用的是 angular。 Angular 通过 api 路由(使用 ADmad JWT 插件)连接到后端,并且应该登录以获取令牌。

我的Api/UsersController.php

public function token()

    $user = $this->Auth->identify();
    if (!$user) 
        throw new UnauthorizedException('Invalid username or password');
    
    $this->set([
        'success' => true,
        'data' => [
            'token' => JWT::encode(
                [
                    'sub' => $user['id'],
                    'exp' =>  time() + 604800
                ],
                Security::salt()
            )
        ],
        '_serialize' => ['success', 'data']
    ]);

现在,当我想测试与 Postman 的连接时,(使用以下选项)它可以工作:

Request-Type: POST
URL:          http://cake3api.app/api/users/token.json
Headers:      Accept       => application/vnd.api+json
              Content-Type => application/vnd.api+json
Body (JSON array):

    "username":"test",
    "password":"1234"

答案:

 
     "success": true,
     "data": 
         "token": "HERE_COMES_THE_TOKEN_AS_ANSWER"
      
 

现在我想将此 auth-api 与 Angular4 一起使用。我创建了一个AuthService,所以我可以向 cake-api 承诺:

import  Injectable  from '@angular/core';
import  Headers, Http  from '@angular/http';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class AuthService 

    private BASE_URL: string = 'http://cake3api.app/api/users';
    private headers: Headers = new Headers(
        'Content-Type' : 'application/vnd.api+json',
        'Accept' : 'application/vnd.api+json'
    );

    constructor(private http: Http)  

    login(user): Promise<any> 
        let url: string = `$this.BASE_URL/token.json`;
        return this.http.post(url, user, headers: this.headers).toPromise();
    

我正在LoginComponent 中调用该服务

import  Component, OnInit  from '@angular/core';
import  AuthService  from '../../services/auth.service';

@Component(
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.css']
)

export class LoginComponent implements OnInit 

    constructor(private auth: AuthService)  

    ngOnInit(): void 
        let sampleUser: any = 
            username: 'test' as string,
            password: '1234' as string
        ;

        this.auth.login(sampleUser).then((user) => 
            console.log(user.json());
        ).catch((err) => 
            console.log(err);
        );
    


有了这个,我收到以下信息:

OPTIONS http://cake3api.app/api/users/token.json 401 (Unauthorized)

未能加载 http://cake3api.app/api/users/token.json:响应 预检具有无效的 HTTP 状态代码 401

// XHR Request & Response (from console)
**GENERAL**
Request URL:http://cake3api.app/api/users/token.json
Request Method:OPTIONS
Status Code:401 Unauthorized
Remote Address:127.0.0.1:80
Referrer Policy:no-referrer-when-downgrade

**RESPONSE HEADERS**
Access-Control-Allow-Headers:origin, x-requested-with, content-type
Access-Control-Allow-Methods:PUT, GET, POST, DELETE, OPTIONS
Access-Control-Allow-Origin:*
Connection:Keep-Alive
Content-Length:247
Content-Type:application/json; charset=UTF-8
Date:Fri, 27 Oct 2017 08:56:17 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.27 (Win32) OpenSSL/1.0.2l PHP/7.1.9
X-DEBUGKIT-ID:ac7b0f38-4c97-44d4-8c26-9f95b94ce937
X-Powered-By:PHP/7.1.9

**REQUEST HEADERS**
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,bs;q=0.2
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:cake3api.app
Origin:http://localhost:4200
Pragma:no-cache
Referer:http://localhost:4200/login
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36

任何人有一个想法,为什么这个星座不工作?我的想法是,角度没有按应有的方式发送请求(发送了错误的标头?)。奇怪的是,我对邮递员的测试有效,但不是 angular。

如果有人认为这是因为 cake 不接受 ORIGIN 标头,那么它应该。我在 ./.htaccess 中启用了访问控制

<IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
    Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
</IfModule>

编辑

因为问题似乎出在发送OPTIONS-request的浏览器上,所以我绕过了,但还是不行。

RewriteEngine On
RewriteCond %REQUEST_METHOD OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

错误消息消失了,但出现了新消息:

未能加载http://cake3api.app/api/users/token.json:响应 预检请求未通过访问控制检查:否 请求中存在“Access-Control-Allow-Origin”标头 资源。因此不允许使用原点“http://localhost:4200” 访问。

现在它说标题Access-Control-Allow-Origin 没有设置。但是我已经将它设置在同一个.htaccess 文件中,我将OPTIONS-request 解决方法放在那里。多么令人不安的问题,已经为这么小的事情浪费了很多时间......

【问题讨论】:

更新:当我使用禁用 CORS 的 chrome 时,它​​可以工作。 chrome.exe --user-data-dir="C:/ChromeDevSession" --disable-web-security 如果它说标题不存在,很可能这是真的。检查您的服务器响应以确定标头是否存在。另请查看 github.com/snelg/cakephp-corsgithub.com/ozee31/cakephp-cors 以了解在 CakePHP 端处理 CORS OPTIONS 请求的实现。 您的服务器配置错误,要求对 OPTIONS 请求进行身份验证。解决方案是将该服务器配置为不需要对 OPTIONS 请求进行身份验证。因为您的浏览器在从您的代码尝试 POST 之前发送 CORS 预检 OPTIONS 请求;但是当您的浏览器发送该 OPTIONS 请求时,它(根据设计)在请求中不包含任何凭据。 【参考方案1】:

未能加载http://cake3api.app/api/users/token.json:响应 预检具有无效的 HTTP 状态代码 401

正如你所说,邮递员能够在通过浏览器收到上述异常时从服务器接收正确的响应,这已经解释了根本问题是什么。

预检请求是浏览器在您的实际请求之前发出的 HTTP OPTION 类型请求,该错误表示您没有明确处理 OPTION 请求。

确保您的 php 服务器接受 OPTION 请求并且它应该可以工作

编辑: 尝试为标头 Access-Control-Allow-Origin' 添加主机而不是通配符 *

Header set Access-Control-Allow-Origin "http://localhost:4200"

并检查 chrome 开发工具中的 HTTP 响应标头,确保您拥有正确的标头。

【讨论】:

我更新了我的帖子。你给了我下一个提示。我认为离目标只差一步了。 :)【参考方案2】:

在您的配置方法中添加httpsercurity.cors 以避免预飞行。

【讨论】:

我对这个话题很感兴趣,但目前我不清楚如何在创建问题的配置方法中添加httpsercurity.cors。你能为我提供更多的背景信息吗?非常感谢! 建议使用spring boot 解决方案,用户需要在php中做同样的事情来解决这个问题。

以上是关于Angular JWT Auth - 总是 401 未经授权的主要内容,如果未能解决你的问题,请参考以下文章

Symfony4 + jwt-auth rescipe 总是返回 "code":401,"message":"Bad credentials"

Nest.js Auth Guard JWT 身份验证不断返回 401 未授权

Angular Detect 401 Unauthorized Access 使用 JWT

即使使用 ASP.NET CORE 登录,我在 Angular 中也有 401 Unauthorized

护照-jwt 总是返回 401 未授权

Angular 2 JWT AuthHttp 错误 401 未捕获