首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用JWT保护EndPoints (JSON令牌)

用JWT保护EndPoints (JSON令牌)
EN

Stack Overflow用户
提问于 2020-09-29 11:47:53
回答 1查看 931关注 0票数 0

编辑了附加信息:错误仍然存在..

我正在用CakePHP BackEnd和Vue FrontEnd开发一个应用程序,并且正在用JWT安全保护API BackEnd。为此,我使用'ADmad/JwtAuth.Jwt‘插件,但我相信您不需要知道这个插件才能回答这个问题。基本思想是,在登录/注册时,客户端接收一个JWT令牌,将其存储在cookie/ session中,然后在随后对API的请求中使用它。

插件加载在我的AppController中,我的API秘密存储在app.php中。

代码语言:javascript
复制
        $this->loadComponent('Auth', [
            'storage' => 'Memory',
            'authenticate' => [
                'ADmad/JwtAuth.Jwt' => [
                    'parameter' => 'token',
                    'userModel' => 'Users',
                    'fields' => [
                        'email' => 'id'
                    ],

                    'queryDatasource' => true
                ]
            ],
            'checkAuthIn' => 'Controller.initialize',
        ]);    

在登录、通过表单/ facebook或注册时,将生成JWT并将其发送到客户端。我将通过登录操作来说明这一点,facebook登录和注册也是类似的。这些是允许在UsersController上执行的操作,其余的都由JWT Auth插件保护。

代码语言:javascript
复制
$this->Auth->allow(['login', 'register', 'facebooklogin', 'getfbcredentials']);  

在客户端(Vue),函数loginUser从表单中获取电子邮件/密码凭据,并将它们发送给API。在服务器端(Cake ),哈希密码在DB中使用值进行检查,并将邮件/密码凭据连同过期日期一起发送回服务器端环境变量的api机密加密。

在客户端,对这些凭据进行解密,并将其与原始邮件/密码值进行比较,以确保外部攻击者没有篡改它们。只有这样,才允许登录并将令牌存储在cookie中。

我不能100%确定是否最好将它们存储在cookie或会话存储中,但是httponly cookie似乎是一样的,我选择了这个选项,因为我阅读了赞成和反对这两种情况的参数。https://dzone.com/articles/cookies-vs-tokens-the-definitive-guide

客户端Vue获取交互。

代码语言:javascript
复制
methods: {
    
    loginUser(){
        
        this.errors = "";
        
        // if one of the mandatory fields is empty 
        if(!this.email || !this.password){
            
            this.errors = "fill in all fields with an *";
            
        // make the API call     
        } else {
            
            // cannot use associative arrays in Javascript : does not exist!! 
            this.data[0] = this.email;
            this.data[1] = this.password;            

            fetch(this.$baseURL + '/users/login', {
              method: 'POST',
              mode: 'cors',
              headers: {
                'Content-Type': 'application/json',
              },
              body: JSON.stringify(this.data),
            })
            .then(response => response.json())
            .then(json_data => {
                
                // console.log(json_data);
                
                // wrong password
                if(json_data == 2){
                    
                    this.errors = "wrong password, please correct."      
                    this.password = ""; 
                    
                // email not found     
                } else if (json_data == 0){
                    
                    this.errors = "email not registered, please register.."    
                
                // succesful save     
                } else if (json_data[0] == 1) {
                            
                    // perform JWT token check, store it & use it in subsequent API calls.. 
                    var payload = this.parseJwt(json_data[2]);                  
                                
                    this.$session.set('isLogged', true); 
                    this.$session.set('user', json_data[1]);
                    this.$session.set('navigateto', 'userhub'); 
                    this.$emit('navEvent');

                    this.errors = "welcome!" 
                    this.email = this.password = "";   

                    // (XSFR attack vulnerability cookie, protected through CORS :: XSS no vulnerability with cookie) 
                    this.$cookies.set('jwtoken', json_data[2], {httpOnly: true});
                            
                }
                
            })
            .catch(error => {

                // console.log("error");
                this.errors = "no success.. please try again."  

            });                        
        }
    },

API-side (Cake)交互,登录操作UsersController:

代码语言:javascript
复制
// loginaction needs to be the same, is defined in AppController 
public function login(){

    $data = $this->request->data; 
    $sendback = [];
    $hasher = new DefaultPasswordHasher();
    
    // no automatic view, only data returned
    $this->autoRender = false;        
    
    // mandatory check to prevent server timeout 
    if($data){
              
        $users = $this->Users->find('all');
        
        foreach($users as $user):

            if ($user['email'] === $data[0]){

                if ($hasher -> check($data[1], $user['password'])){

                    // get user id, this is the user given you implement a check for double entries 
                    // never a password in storage!!!! 
                    $user['password'] = "";
                    $user['resetcode'] = "";
                    
                    // JWT Encode the payload/ secret to generate token..
                    // secret from environment variables, not known to the attacker, needs to know this to form the token or steal the token.. 
                    $apisecret = Configure::read('apisecret');  
                    $payload = ['mail' => $data[0], 'password' => $data[1],'exp' =>  time() + 604800, 'id' => $user['id'], 'sub' => $user['id']];
                    
                    // uses salt value in app.php for encryption::encryption mechanism uses firebase library combined with salt value..  
                    $jwt = JWT::encode([$payload, $apisecret], Security::salt());
                    
                    $sendback[0] = 1;
                    $sendback[1] = $jwt;

                // wrong password 
                } else {

                    $sendback[0] = 2;

                }
                
                // break actually does the same as a $this->Users->find('first') with condition email.. 
                // break the loop whenever email is found, run password check 1 time.. 
                break;                    

            } else {

                $sendback[0] = 0;

            }

        endforeach;        
        
    }   
         
    return $this->response
    ->withType('application/json')
    ->withStringBody(json_encode($sendback));              
                
}

到目前为止还不错..。-)现在我想在后面的API请求中对后端使用这个cookie。因此,我在获取请求的授权头中设置从cookie检索的JWT。我的后端出现了一个错误,上面写着“您无权访问该位置”。(错误日志底部页)。

代码语言:javascript
复制
fetch(this.$baseURL + '/holidays', {
      method: 'POST',
      mode: 'cors',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + this.$cookies.get("jwtoken"),
      },
      body: JSON.stringify(this.data),
    })
    .then(response => response.json())
    .then(json_data => {
        
        // console.log(json_data);
        
    })
    .catch(error => {

        this.errors = "no success.. please try again."

    });

错误日志

代码语言:javascript
复制
2020-09-29 11:44:14 Error: [Cake\Http\Exception\UnauthorizedException] You are not authorized to access that location. (C:\wampserver\www\wamp_projects\holidays_backend\vendor\admad\cakephp-jwt-auth\src\Auth\JwtAuthenticate.php:264)
#0 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Controller\Component\AuthComponent.php(387): ADmad\JwtAuth\Auth\JwtAuthenticate->unauthenticated(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#1 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Controller\Component\AuthComponent.php(315): Cake\Controller\Component\AuthComponent->_unauthenticated(Object(App\Controller\UsersController))
#2 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Event\EventManager.php(352): Cake\Controller\Component\AuthComponent->authCheck(Object(Cake\Event\Event))
#3 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Event\EventManager.php(329): Cake\Event\EventManager->_callListener(Array, Object(Cake\Event\Event))
#4 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Event\EventDispatcherTrait.php(113): Cake\Event\EventManager->dispatch(Object(Cake\Event\Event))
#5 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Controller\Controller.php(676): Cake\Controller\Controller->dispatchEvent('Controller.init...')
#6 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\ActionDispatcher.php(115): Cake\Controller\Controller->startupProcess()
#7 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\ActionDispatcher.php(94): Cake\Http\ActionDispatcher->_invoke(Object(App\Controller\UsersController))
#8 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\BaseApplication.php(234): Cake\Http\ActionDispatcher->dispatch(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#9 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\Runner.php(65): Cake\Http\BaseApplication->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#10 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Routing\Middleware\RoutingMiddleware.php(162): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#11 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\Runner.php(65): Cake\Routing\Middleware\RoutingMiddleware->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#12 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Routing\Middleware\AssetMiddleware.php(88): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#13 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\Runner.php(65): Cake\Routing\Middleware\AssetMiddleware->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#14 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Error\Middleware\ErrorHandlerMiddleware.php(96): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#15 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\Runner.php(65): Cake\Error\Middleware\ErrorHandlerMiddleware->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#16 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\debug_kit\src\Middleware\DebugKitMiddleware.php(53): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#17 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\Runner.php(65): DebugKit\Middleware\DebugKitMiddleware->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#18 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\Runner.php(51): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#19 C:\wampserver\www\wamp_projects\holidays_backend\vendor\cakephp\cakephp\src\Http\Server.php(97): Cake\Http\Runner->run(Object(Cake\Http\MiddlewareQueue), Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#20 C:\wampserver\www\wamp_projects\holidays_backend\webroot\index.php(40): Cake\Http\Server->run()
#21 {main}
Request URL: /users/retrievepicture
Referer URL: http://localhost:8080/

我在使用JSON令牌时做错了什么?我认为我的授权头中有错误,但不确定。有谁可以帮我?

EN

回答 1

Stack Overflow用户

发布于 2020-09-30 06:25:35

从Packege 文档和一个简单但很好的解释教程,我建议您添加

代码语言:javascript
复制
'storage' => 'Memory',
'checkAuthIn' => 'Controller.initialize',

$this->loadComponent('Auth',.)

同样,在创建令牌时,在有效负载中添加用户id,如下所示

代码语言:javascript
复制
payload = ['id' => $user['id'],'sub' => $user['id'] ,'mail' => $data[0], 'password' => $data[1],'exp' =>  time() + 3600];

还请您遵循上述教程链接,以更好地理解。

编辑:如果这个问题仍然存在,请

  • 检查Vue是否在API请求中发送令牌
  • 对于调试,Auth允许该方法将/holidays请求绑定到并通过 $header =$request->getHeaderLine(‘授权’);
  • 在控制器方法中打印$header,以查看CakePHP是否接收到授权头。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64118987

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档