Am using angular2 and yii2 restful services but it fails
This is my angular2 part
In the userservice
constructor(private http:HttpClientService, private _domaindetails:Domaindetails) { }
profile(val:string="profile"):Observable<User>{
return this.http.get(this.getUserUrl(val))
.map(this.extractData)
}
This is the httpclientService
createAuthorizationHeader(headers: Headers) {
let token = JSON.parse(localStorage.getItem("currentUser")).token;
if (token) {
headers.append('Authorization', 'Bearer ' + token);
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Content-Type', 'application/json');
}
}
post(url, data) {
let headers = new Headers();
this.createAuthorizationHeader(headers);
return this.http.post(url, data, {
headers: headers
});
}
This is my backend In Yii2
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['corsFilter'] = [
'class' => \yii\filters\Cors::className(),
'cors' => [
// restrict access to
'Origin' => ['http://localhost:4200'],
'Access-Control-Request-Method' => ['POST', 'GET','PUT'],
// Allow only POST and PUT methods
'Access-Control-Request-Headers' => ['*'],
// Allow only headers 'X-Wsse'
// 'Access-Control-Allow-Credentials' => true,
// Allow OPTIONS caching
'Access-Control-Max-Age' => 3600,
// Allow the X-Pagination-Current-Page header to be exposed to the browser.
'Access-Control-Expose-Headers' => ['X-Pagination-Current-Page'],
],
];
$auth = $behaviors['authenticator'] = [
'class' => HttpBearerAuth::className(),
'only' => ['can-access','profile'], //access controller
];
$behaviors['authenticator']['except'] = ['options'];
return $behaviors;
}
And the yii2 action fails returning an error of unauthorized access
public function actionProfile()
{
$user = Yii::$app->user->identity;
return ['data' => $user];
}
When i check Yii::$app->request->headers;
As you can see the bearer token is set
This is my usermodel
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['auth_key' => $token]); //auth_key is the value used in bearer token
}
Why does it keep on returning an error 401 unauthorized access and yet when i use the same value of authkey and set authorization bearer headers in postman it works
After a few research i found out that the whenever angular2 makes a request it sends an options request which fails
For those who might face this problem i found out that this was caused by the HttpBearerAuth and when i changed to QueryParamAuth
everything is now working i also made a few other changes as
ON THE CONTROLLER
1.Removed the cors filters
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => CompositeAuth::className(),
'authMethods' => [
HttpBasicAuth::className(),
HttpBearerAuth::className(),
QueryParamAuth::className(),
],
];
return $behaviors;
}
2,In my config main.php
'response' => [
'format' => yii\web\Response::FORMAT_JSON,
'charset' => 'UTF-8',
'on beforeSend' => function ($event) {
header("Access-Control-Allow-Origin: *");
}
],
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => 'auth', 'pluralize'=>false],
...other controlers here
],
],
3.In the .htacess file in the project root i added
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Content-Type"
So my angular2 post request looks like
http://127.0.0.1/bcl/api/rest/v1/auth/logout?access-token=your access token
So the access token is always passed as a query parameter
The main reason is because i found out that if the browser sends any header apart from content type an options request is triggered
So now my headers look like
headers.append('Content-Type', 'application/x-www-form-urlencoded');
//i removed the bearer token
I used a different approach:
Added
public function beforeAction($action)
{
$this->enableCsrfValidation = false;
parent::beforeAction($action);
if (Yii::$app->getRequest()->getMethod() === 'OPTIONS') {
// End it, otherwise a 401 will be shown.
Yii::$app->end();
}
return true;
}
in the controller.
Keep the behaviours function as at your question.
As you mentioned, the issue is that the browser sends a preflighted request.
My assumption is that you are making a cross browser request(localhost:4200), so the browser is making an OPTIONS request first to the server to find out the "Access-Control-Allow" settings, but without an access token in the header. So a 401 is thrown and the CORS process fails.
The difference is that this way, you can have the authorization token in a header.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With