ASP.Net WebAPI Owin Authentication Attribute knocked out
I am trying to create a demo project that uses .Net ASP.Net WebAPI and KnockoutJs as an interface. I have created controller methods that listen for message / token and validate the user and return a token. This is done from the Ajax Post from the knockout view model.
This code works. However, when I get 200 back (Success) from webApi, I then redirect to the controller method decorated with [Authorize]. And where I hit 401 - not authorized.
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";
});
}
I think the problem is that I am getting a response from my / token (login) but not doing anything with it. I'm not sure what to do with the token. I foolishly thought that Oout somehow put a token in my headers and they'll be magical there. I was wrong.
So I was looking for an example and then the best way is to find Here
But this means that I will have a lot of repetitive code, on each view model
Extract:
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);
This seems to be part of what I am missing:
sessionStorage.setItem(tokenKey, data.access_token);
var tkn = sessionStorage.getItem(tokenKey);
$("#tknKey").val(tkn);
Do I need each view model to have code that is then sent to sessionStorage and receives a token?
So this:
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);
}
Seems like a lot of code. Is it correct?
source to share
So what you can do is attach a bearer token to each of your HTTP requests. I'm assuming you are using jQuery? Use a config optionbeforeSend
if possible .
Extract the reuse method like:
function onBeforeSend(xhr, settings) {
var token = sessionStorage.getItem(tokenKey);
if (token) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token );
}
}
And then just attach this method to each of your calls $.ajax
that require a token, for example:
$.ajax({
type: 'GET',
url: '/api/values',
headers: headers,
beforeSend: onBeforeSend
}).done(function (data) {
self.result(data);
}).fail(showError);
The function onBeforeSend
obviously needs to be accessible by your ajax call (I'm not a knockout, so I don't know if it has any constructs like services, but if not, you can, for example, to not make it a global function. but your code organization is up to you).
This way, you will need to add a bit beforeSend: onBeforeSend
for each request that requires authorization, and this will avoid unnecessary duplication of code.
source to share