【问题标题】:Unexpected behaviour with extended BaseRequestOptions in Angular2 AppAngular2 App 中扩展 BaseRequestOptions 的意外行为
【发布时间】:2016-06-22 21:54:28
【问题描述】:

我有一个与 ASP.Net MVC 后端通信的 angular2 应用程序。 后端要求 AntiForgeryToken 出现在 POST 请求上。

为此,我的index.html 提供了一个隐藏输入,其值代表令牌。我想这是ASP.Net MVC 项目中的常用方法(不是这个问题的主题)。

现在要获取此令牌并在我的请求标头中使用它,我在 main.ts 中扩展了 BaseRequestOptions,如下所示:

@Injectable()
class AntiForgeryRequestOptions extends BaseRequestOptions {
    constructor () {
        super();
        let xsrfElement = <HTMLInputElement>document.querySelector('[name=__RequestVerificationToken]');
        if (xsrfElement) {
            let xsrfToken:string = xsrfElement.value;
            this.headers.append('X-XSRF-Token', xsrfToken);
        }
        this.headers.append('Content-Type', 'application/json');
    }
}

并将其提供为RequestOptions,如下所示:

bootstrap(AppComponent, [
    ...
    provide(RequestOptions, {useClass: AntiForgeryRequestOptions}),
    ...
]);

有了这个设置,我可以像这样在我的服务中发出POST-requests:

post(url:string, body:any):Observable<any> {
        let options = new RequestOptions();

        return this._http.post(url, body, options)
            .map((response:any) => {
                ...
            })
            .catch(this._handleError);
    }

效果很好。 POST 有效,CSRF Token 随它一起发送。


问题

今天我不得不对此进行调整,因为我必须在某些情况下关闭令牌并遇到一些我无法解释的奇怪行为:

根据我的理解,一旦我这样做:let options = new RequestOptions() 的构造函数应该已经被调用,AntiForgeryRequestOptions 的构造函数应该被设置为这个RequestOptions 我刚刚创建的。但是,如果我在通话后直接执行console.log(options),我会看到所有属性都是NULL,甚至是标题。 (它仍然有效,CSRF Token 已发送,其 content-typeapplication/json)但我无法访问它或为即将到来的请求更改它。

谁能告诉我为什么会发生这种情况,或者我将如何更改我之前在AntiForgeryRequestOptions 的构造函数中定义的RequestOptions


附加信息:

我这样做是有原因的。当我开始这个项目时,angular2 仍处于 beta 状态(现在我正在使用 angular2 rc1)。当时CSRF Tokens 存在问题,您无法直接在选项中进行设置。现在有了新版本,我不需要提供自定义AntiForgeryRequestOptions。我可以把它放在一边,然后在帖子请求中这样做:

post(url:string, body:any):Observable<any> {
        let options = new RequestOptions();
        options.headers = new Headers();
        let xsrfElement = <HTMLInputElement>document.querySelector('[name=__RequestVerificationToken]');
        if (xsrfElement) {
            let xsrfToken:string = xsrfElement.value;
            options.headers.append('X-XSRF-Token', xsrfToken);
        }
        options.headers.append('Content-Type', 'application/json');

        ...
    }

解决方案

正如 Günther 在他的评论中建议的那样,我必须在我的自定义 AntiForgeryRequestOptions 中使用 merge,如下所示:

@Injectable()
class AntiForgeryRequestOptions extends BaseRequestOptions {
    constructor () {
        super();
    }

    merge(options?:RequestOptionsArgs):RequestOptions {
        options.headers = new Headers();
        let xsrfElement = <HTMLInputElement>document.querySelector('[name=__RequestVerificationToken]');
        if (xsrfElement) {
            let xsrfToken:string = xsrfElement.value;
            options.headers.append('X-XSRF-Token', xsrfToken);
        }
        options.headers.append('Content-Type', 'application/json');
        return super.merge(options);
    }
}

有效。现在,每次我调用new RequestOptions() 时,Headers 属性都会正确更新,这意味着每当我更改 CSRF 令牌的隐藏输入字段的值时,标题都会按应有的方式进行调整。

【问题讨论】:

  • 我认为你需要添加merge(),如stackoverflow.com/questions/37549599/…所示
  • 谢谢,这有效。我调整了我的问题。如果你愿意,你可以用它来提供一个“真实”的答案。不过,真的不明白为什么因为调用new RequestOptions() 应该调用这个构造函数..也许有人会为此提供更多信息:)

标签: asp.net asp.net-mvc angular csrf-protection


【解决方案1】:

您需要实现一个自定义的merge(options?: RequestOptionsArgs): RequestOptions { ... } 方法,因为默认实现只是检查是否将标头传递给merge(...),然后获取这些标头,否则将获取当前AntiForgeryRequestOptions 实例的标头,但 id 实际上并未合并.

另见https://github.com/angular/angular/blob/f39c9c9e75671a7e235734b6b8aef263f6dff254/modules/%40angular/http/src/base_request_options.ts#L101

示例(来自问题 - 感谢您的许可)

@Injectable()
class AntiForgeryRequestOptions extends BaseRequestOptions {
    constructor () {
        super();
    }

    merge(options?:RequestOptionsArgs):RequestOptions {
        options.headers = new Headers();
        let xsrfElement = <HTMLInputElement>document.querySelector('[name=__RequestVerificationToken]');
        if (xsrfElement) {
            let xsrfToken:string = xsrfElement.value;
            options.headers.append('X-XSRF-Token', xsrfToken);
        }
        options.headers.append('Content-Type', 'application/json');
        return super.merge(options);
    }
}

另见https://stackoverflow.com/a/37550368/217408

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-10
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    • 2023-03-11
    • 2017-08-27
    • 2021-12-08
    相关资源
    最近更新 更多