带有LexikJWTAuthenticationBundle的Symfony3 JWT在Preflight OPTIONS上返回404

时间:2017-01-20 13:54:17

标签: typescript cors ionic2 symfony lexikjwtauthbundle

说明

我正在使用LexikJWTAuthenticationBundle并尝试使用从Ionic2应用程序发送的凭据生成JWT令牌。

使用Curl和Postman生成令牌可以正常工作。

curl -X POST http://localhost:8000/api/login_check -d _username=root -d _password=root

但是,Ionic2在实际发送带有凭据的POST请求之前发送了预检OPTIONS请求。 Symfony3误解了这一点并发回了404。

来自Ionic2的

控制台错误:

  

选项http://localhost:8000/api/login_check 404(未找到)   XMLHttpRequest无法加载http://localhost:8000/api/login_check

     

对预检请求的响应未通过访问控制检查:否   请求中存在“Access-Control-Allow-Origin”标头   资源。因此不允许来源“http://localhost:8100”   访问。响应的HTTP状态代码为404.

     

0 - {“isTrusted”:true}

     

EXCEPTION:0 - {“isTrusted”:true}

问题:

我的Symfony3应用程序(可能是我的routing.yml或security.yml中的某些内容)必须更改为不发回404?

代码:

Ionic2 HttpService:

 @Injectable()
 export class HttpService {

  private baseUrl: string = "http://localhost:8000";

  constructor(private http: Http){

  }

  public create<T>(url: string, extractData, data: any = null): Observable<Array<T>>{

    let headers = new Headers({ 'Content-Type': 'application/json'});
    let options = new RequestOptions({ headers: headers });

    return this.http
      .post(this.baseUrl + url, data, options)
      .map(extractData)
      .catch(this.handleError)
  }
  //More methods here...
 }

Symfony routing.yml:

api_login_check:
    path: /api/login_check
    # This line is something I added to see if OPTIONS would work
    # However, it did not work.
    methods:  [POST, OPTIONS]

类似的问题:

Symfony2 JWT Authentication Returning 404 on Preflight

2 个答案:

答案 0 :(得分:1)

在适当的标题处查看https://github.com/nelmio/NelmioCorsBundle。服务器需要使用适当的Access-Control-Allow原始响应标头进行响应,例如:

Access-Control-Allow-Origin:http://localhost:8100

允许请求成功。

有关CORS行为的更多信息:https://www.moesif.com/blog/technical/cors/Authoritative-Guide-to-CORS-Cross-Origin-Resource-Sharing-for-REST-APIs/

答案 1 :(得分:1)

说明:

因此,在这个问题上打了一整天之后,我找到了解决方案。虽然可以合并NelmioCorsBundle(不确定它是否支持Symfony3),但我发现它只是为了绕过Cors问题而过度杀伤。

在真实世界的手机应用程序中,不会发送OPTIONS预检请求。这仅适用于ionic serve(根据我的理解)。

我们的想法是为Ionic2设置代理服务器..说起来容易做起来难。关于它似乎有很多问题。我已经能够让它工作了。

解决方案:

Ionic2项目的根目录下应该有一个ionic.config.json。你只需要添加几行:

{
  "name": "websurgapp",
  "app_id": "",
  "v2": true,
  "typescript": true,
  //This is what I added.
  "proxies": [{
    "path": "*/api", //<- NOTICE THE */ !
    "proxyUrl": "http://localhost:8000/api"
  }]
}

然后简单地发送请求:

<强> HttpService的:

@Injectable()
export class HttpService {http://localhost:8000;
  constructor(private http: Http){
  }
  public create<T>(url: string, data: any = null, contentType: string = 'application/json'): Observable<Array<T>>{
    let headers = new Headers({ 'Content-Type': contentType});
    let options = new RequestOptions({ headers: headers });
    console.log(data);
    return this.http
      .post(url, data, options)
      .map((res:Response)=>res.json())
      .catch(this.handleError)
  }
}

<强> AuthService:

@Injectable()
export class AuthService {
  constructor(public httpService: HttpService) {
    console.log('Hello AuthService Provider');
  }
  private currentUser: User;
  public login(credentials): any {
    console.log("Login called.");
    //TODO: Upgrade symfony to 3.3 to be able to use JSON.
    let body = new URLSearchParams();
    body.append('_username', credentials._username);
    body.append('_password', credentials._password);
    let result = this.httpService.create("/api/login_check", body, 'application/x-www-form-urlencoded');
    return result;
  }
 }

注意我不会在我的请求中发送JSON。捆绑包当前不支持它。但是,symfony版本3.3。(我在3.1。上)支持它。

打破它:

  1. 我的symfony应用程序在http://localhost:8000
  2. 上运行
  3. 我的Ionic 2应用程序在http://localhost:8100
  4. 上运行
    "path": "*/api" 
    

    简单地说明,无论我们发出的具有“/ api /”的请求将被转换为proxyUrl。

    例如,要生成令牌,我需要将我的凭据发送到"/api/login_check"

    我之前尝试的内容:

    我之前一直在向http://localhost:8000/api/login_check发送请求,这当然会发送预检OPTIONS请求,导致一大堆错误。

    然后我尝试简单地指定“/ api / login_check”,但http请求会添加"http://localhost:8100" infront ..我的应用程序向自己发送请求..这当然不起作用。

    解决方案解释:

    在代理服务器启动的情况下,我只是向"/api/login_check"发送请求而没有任何内容,它会以POST request的形式发送到我的symfony3应用程序,而不会preflight OPTIONS request.