使用其他信息进行了编辑:错误仍然存在。
我正在使用CakePHP BackEnd和Vue FrontEnd开发一个应用程序,并且正在使用JWT Security保护我的API后端。为此,我使用的是“ ADmad / JwtAuth.Jwt”插件,但我相信您不需要知道此插件即可回答问题。基本思想是,在登录/注册时,客户端会收到一个JWT令牌,将其存储在cookie /会话中,然后在对API的后续请求中使用它。
该插件已加载到我的AppController中,我的API机密存储在了app.php中。
$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插件保护。.
$this->Auth->allow(['login', 'register', 'facebooklogin', 'getfbcredentials']);
在客户端(Vue)上,函数loginUser从表单中获取电子邮件/密码凭据,并将其发送到API。在服务器端(Cake API),将使用数据库中的值检查哈希密码,并使用来自服务器端环境变量的api secret加密将邮件/密码凭据以及到期日期发送回去。
在客户端,这些凭据被解密并与原始邮件/密码值进行比较,以确保没有外部攻击者篡改它们。只有这样,才允许登录并将令牌存储在cookie中。
我不确定100%是否最好将它们存储在cookie或sessionstorage中,但是httponly cookie似乎是相同的,并且我选择了此选项,因为我已经阅读了支持和反对两者的论点。 https://dzone.com/articles/cookies-vs-tokens-the-definitive-guide
客户端Vue获取交互。.
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端(Cake)交互,登录操作UsersController:
// 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。.我在后端收到一条错误消息,指出“您无权访问该位置”。 (错误日志底部页面)..
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."
});
错误日志
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 Web令牌时我做错了什么?我认为我的授权标头中有错误,但不确定。有人可以帮助我吗?
答案 0 :(得分:0)
从Packege Documentation和一个简单但很好的解释tutorial中,我建议您添加
'storage' => 'Memory',
'checkAuthIn' => 'Controller.initialize',
在您的 $ this-> loadComponent('Auth',...)
另外,当您创建令牌时,在这样的有效载荷中添加用户ID ,子
payload = ['id' => $user['id'],'sub' => $user['id'] ,'mail' => $data[0], 'password' => $data[1],'exp' => time() + 3600];
也请您按照上面的教程链接进行操作,以更好地理解
。编辑:如果此问题仍然存在,请
检查Vue是否在API请求中发送令牌
对于调试,Auth允许将该方法绑定到/ holidays请求并通过以下方法检查标头
$ header = $ request-> getHeaderLine('Authorization');
在控制器方法中打印$ header,以查看CakePHP是否收到授权头。