Knockout中的ASP.Net WebAPI Owin身份验证令牌

时间:2017-03-22 23:33:36

标签: c# asp.net asp.net-web-api knockout.js

我正在尝试创建一个使用.Net ASP.Net WebAPI和KnockoutJs作为前端的演示项目。我创建了监听/ token帖子的控制器方法,并验证用户,并返回一个令牌。这是通过Knockout View Model的Ajax Post完成的。​​

此代码有效。但是,当我从webApi获得200返回(成功)时,我然后重定向到一个控制器方法,用[Authorize]装饰。那就是我打到401的地方 - 未经授权。

Login()
    {
        var data = {
            username : this.login.emailAddress(),
            password : this.login.password(),
            RememberMe: this.login.rememberMe(),
            grant_type: "password"
        }

        return $.ajax({
            type: "POST",
            data: data,
            dataType: "json",
            url: "/token",
            contentType: "application/json"
        }).done((reply) => {
            window.location.href = "/Home/AnotherThing";
        });

    }

我认为问题是 - 我从/ token(登录)调用得到了回复,但是没有做任何事情。我不知道如何处理令牌。我愚蠢地认为OAuth会以某种方式将令牌放入我的标题中,并且它们会神奇地存在。我错了。

所以,我一直在寻找一个例子,然后我能找到的最好的是Here

但这意味着我将在每个视图模型上有很多重复的代码

提取物:

function ViewModel() {  
    var self = this;  

    var tokenKey = 'accessToken';  
    var RefTokenKey = 'refreshToken';  
    self.result = ko.observable();  
    self.user = ko.observable();  

    self.token = ko.observable();  
    self.refreshToken = ko.observable();  

    function showError(jqXHR) {  
        self.result(jqXHR.status + ': ' + jqXHR.statusText);  
    }  

    self.callApi = function () {  

        self.result('');  

        var token = sessionStorage.getItem(tokenKey);  

        var headers = {};  
        if (token) {  
            headers.Authorization = 'Bearer ' + token;  
        }  

        $.ajax({  
            type: 'GET',  
            url: '/api/values',  
            headers: headers  
        }).done(function (data) {  
            self.result(data);  
        }).fail(showError);  
    }  

    self.callToken = function () {  
        self.result('');  
        var loginData = {  
            grant_type: 'password',  
            username: self.loginEmail(),  
            password: self.loginPassword()  
        };  

        $.ajax({  
            type: 'POST',  
            url: '/Token',  
            data: loginData  
        }).done(function (data) {  
            self.user(data.userName);  
            // Cache the access token in session storage.  
            sessionStorage.setItem(tokenKey, data.access_token);  
            var tkn = sessionStorage.getItem(tokenKey);  
            $("#tknKey").val(tkn);  
        }).fail(showError);  
    }  

}  

var app = new ViewModel();  
ko.applyBindings(app);

这似乎是我所缺少的一部分:

sessionStorage.setItem(tokenKey, data.access_token);  
                var tkn = sessionStorage.getItem(tokenKey);  
                $("#tknKey").val(tkn);  

我是否需要每个视图模型都有代码然后转到sessionStorage并获取令牌?

所以,这个:

var token = sessionStorage.getItem(tokenKey);  

        var headers = {};  
        if (token) {  
            headers.Authorization = 'Bearer ' + token;  
        }  

        $.ajax({  
            type: 'GET',  
            url: '/api/values',  
            headers: headers  
        }).done(function (data) {  
            self.result(data);  
        }).fail(showError);  
    } 

好像很多代码..这是正确的方法吗?

1 个答案:

答案 0 :(得分:3)

好的,您可以做的是将持有者令牌附加到您的每个HTTP请求中。我假设你在那里使用jQuery?如果是这种情况,你可以leverage the beforeSend config param

提取可重用的方法,例如:

function onBeforeSend(xhr, settings) {    
  var token = sessionStorage.getItem(tokenKey);  

  if (token) {  
    xhr.setRequestHeader('Authorization', 'Bearer ' + token ); 
  }  
}

然后只需将该方法附加到需要令牌的每个$.ajax调用中,如下所示:

$.ajax({  
  type: 'GET',  
  url: '/api/values',  
  headers: headers,
  beforeSend: onBeforeSend
}).done(function (data) {  
  self.result(data);  
}).fail(showError);  

onBeforeSend函数显然需要通过你的ajax调用来访问(我不是一个淘汰的人,所以我不知道它是否有任何构造,如服务,但如果没有,你可以命名它例如,为了避免使其成为一个全局函数,但您的代码组织由您决定。)

这样,您只需要为每个需要auth的请求添加beforeSend: onBeforeSend位,这样可以避免不必要的代码重复。