我将Angular7用作前端,将yii2用作后端应用 当我尝试从角度调用api时,它给出了错误消息“ XMLHttpRequest at'http://localhost/pwap/html/api/web/v2/users/login'from origin'http://localhost:4200'”已被CORS策略阻止:对预检请求的响应未通过访问控制检查:它没有HTTP正常状态。”
我为CORS应用了不同的解决方案,但没有成功
我在Yii2后端的htaccess代码如下所示
Header set Access-Control-Allow-Origin "*"
#Header always set Access-Control-Allow-Origin: "http://localhost:4200"
Header set Access-Control-Allow-Methods "POST, GET, PUT, OPTIONS, DELETE"
Header set Access-Control-Max-Age "86400"
Header set Access-Control-Allow-Headers "*"
Header set Access-Control-Request-Headers "*"
如下所示的角度代码
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8, application/json, text/html, text/plain , text/xml',
'app_token': environment.app_token,
'Accept': '*/*',
'Access-Control-Allow-Origin': ['*'],
//'Access-Control-Request-Headers': ['*'],
'Access-Control-Allow-Headers': ['*']
})
};
let data = {
"username": username,
"password": password
}
let params = new URLSearchParams();
for(let key in data){
params.set(key, data[key])
}
return this.http.post('http://localhost/pwap/html/api/web/v2/users/login', data, httpOptions)
.pipe().subscribe(user => {
// login successful if there's a jwt token in the response
if (user) {
console.log(user);
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
//this.currentUserSubject.next(user);
}
return user;
}
);
}
我还传递了“ app_token”标头,该标头未显示在“键:值”对中
我在这里做什么错?需要帮助
答案 0 :(得分:1)
我建议您使用解决方案来设置代理配置。使用angular-cli绕过代理。这样,与API服务器通信的就是Angular CLI服务器。
在项目文件夹中创建代理配置文件:proxy.config.json,其中包含以下内容。
{
"/api/*": {
"target": "http://http://localhost/pwap/html/api/web/v2/users/login",
"secure": false,
"pathRewrite": {"^/api" : ""}
}
}
现在您可以使用以下命令为您的应用服务:
ng serve —-proxy-config proxy.conf.json
请注意,您的请求必须转到“ localhost:4200 / app / {资源名称}”。例如,像这样:
this.httpClient.post('api/users'));
答案 1 :(得分:0)
在api控制器中
public function behaviors()
{
return yii\helpers\ArrayHelper::merge(parent::behaviors(), [
'corsFilter' => [
'class' => yii\filters\Cors::className(),
'cors' => [
'Origin' => ['*'], // or your app adddress specified
'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
'Access-Control-Request-Headers' => ['*'],
'Access-Control-Allow-Credentials' => true
]
]
]);
}
答案 2 :(得分:0)
为了节省一些令人沮丧的长时间可能会有用,我在这里总结了两个对我有用的解决方案,使用 Angular (v11.0.2) 和 Yii2 (v2.0.35)。
使用用户名和密码进行身份验证
我的 OauthController
看起来像这样:
class OauthController extends Controller
{
public static function allowedDomains() {
return [
'http://localhost:4200',
'http://localhost:*',
// '*',
];
}
public function behaviors() {
return array_merge(parent::behaviors(), [
// For cross-domain AJAX request
'corsFilter' => [
'class' => \yii\filters\Cors::class,
'cors' => [
// restrict access to domains:
'Origin' => static::allowedDomains(),
'Access-Control-Request-Method' => ['POST'],
'Access-Control-Allow-Headers' => ['Origin', 'X-Requested-With', 'Content-Type', 'accept', 'Authorization'],
'Access-Control-Allow-Credentials' => true,
'Access-Control-Max-Age' => 3600,
],
],
]);
}
// ...
}
在 Angular 中,我登录添加标头 'Content-Type'
和 Authorization
(即 BasicAuth
):
login(email: string, password: string) {
let httpHeaders = new HttpHeaders();
httpHeaders.append('Content-Type', 'application/json');
httpHeaders.append(
'Authorization',
'Basic ' + btoa(email + ':' + password)
);
const httpOptions = {
headers: httpHeaders,
};
return (
this.http
.post<AuthResponseData>(
"http://your-url",
// Body
{
username: email,
password: password,
},
httpOptions
)
.pipe(
// ...
)
);
}
使用不记名令牌进行身份验证
正如 this 的回答所指出的,Yii2 Bearer 身份验证可能很难用前端框架处理。
就我而言,任何使用 HttpBearerAuth
的尝试都失败了,我改用 QueryParamAuth
。
class SomeController extends \yii\rest\ActiveController
{
public static function allowedDomains() {
return [
// '*', // THIS WILD CARD MAY CREATE PROBLEMS (see notes below)
'http://localhost:4200',
'http://localhost:*',
$_SERVER["REMOTE_ADDR"],
];
}
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => QueryParamAuth::class,
];
$behaviors['corsFilter'] = [
'class' => \yii\filters\Cors::class,
'cors' => [
'Origin' => static::allowedDomains(),
'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
'Access-Control-Allow-Headers' => ['Origin', 'X-Requested-With', 'Content-Type', 'accept', 'Authorization'],
'Access-Control-Allow-Credentials' => true,
'Access-Control-Allow-Credentials' => true,
'Access-Control-Max-Age' => 3600,
],
];
return $behaviors;
}
// ...
}
在 Angular 中,我在 access-token
中设置了查询参数 interceptor
:
let headers = req.headers.append('Content-Type', 'application/json');
const modifiedReq = req.clone({
params: new HttpParams().set('access-token', user.token),
headers: headers,
});
注意事项
通过检查 prepareHeaders(),很明显只有当 '*'
为 'Access-Control-Allow-Credentials'
或未设置时,才允许使用通配符 false
。
查询参数access-token
是Yii2在$tokenParam
类(source code)中设置的QueryParamAuth
的定义
如果有人知道如何使 HttpBearerAuth
与 Angular 一起工作,我将不胜感激。