Reputation: 1159
So far I have mainly been using a single asp.net app metaphor where the razor pages are served together with the data from the same app, so I can protect certain controller actions for the ui and data controller actions using the same security.
My new app has a completely independent api web site (using servicestack) and a different asp.net UI app that consumes the api. Right now the two apps sit on the same server, but I want to support the ability for anybody to write a UI app that consumes my data, so the app could sit anywhere and could be a php app all I care.
The new UI uses razor and MVC but it is really a fully client side app, which requests data from the api site.
So, the problem is right there. I am used to automatically redirecting a page from the server side to the login when someone hasn't logged in yet. My UI's server side has no concept of the login situation of the api web site.
The best I can do right now is, at the begging of ANY UI page's load, to do a lightweight ajax call to the api web site, to get the current user info. If it's null, I do a client side document.location.href = .
This works, but has issues, primarily it causes a lot of client side busy ui stuff. An initial version of the UI loads empty (no data), then an awkward redirect to the login page happens. The client side app becomes chatty - every page that loads does an additional call to the api site. The server side redirect is clean because the first page you see is either the UI page that you already have access to or the login page.
My first question is, what is the best practice to do this kind of stuff? My second question is, is there a client side cookie on my UI page that deterministically tells me I am logged in to the api site? I inspected the cookies on a UI page before and after the login that sets the security to the api site and the cookies seem to be the same. My third question is - is there some kind of security actionfilter I can write for my UI mvc site, which somehow magically determines from the cookies of the request, whether the UI is currently logged in to the api site and if it is, it lets the request serve the page, if not, it does the sever side redirect to the login page.
Thanks
Edit: Scott - thanks so much for the detailed explanation. One clarification - i use mvc only to really serve my client side html. I use all knockoutjs and Ajax calls to servicestack to render the data. My question is really about how to react to Ajax calls that return security exceptions and how to avoid presenting an empty html ui because the user is not logged in. My login page authenticates directly from html to ss bypassing the mvc part. It's not an spa where I can keep a single client side login state that applies to all views of the spa. There are multiple cshtml pages that all need to probe for login in order to not load empty and redirect to the login page...
Upvotes: 1
Views: 169
Reputation: 21501
So the MVC just serves the blank template, that includes the knockout js that will call the API to populate it? I believe this flow shows how your current pages are testing for a session using a lightweight ajax call to the api
.
The problem with that approach as you have noted is that it has overhead, and a noticeable delay if there isn't a session.
You can't test for the ss-id
cookie in your JavaScript client application because of the origin difference. Knowing this cookie exists would give you an indication of whether a user might have a valid session. But seeing you can't access it, you have to work around this. When your login page successfully creates a session by calling the API, you should have the success method create a cookie that denotes that you have a session. Such as a hasSession
cookie.
You can check for this existence of this cookie on each page load. It doesn't involve a server trip to verify it. If that cookie has the same expiration policy as the ServiceStack API cookie, then it should stay in sync.
The initial cshtml page state should hide the unpopulated page form contact using CSS, and show a loading indicator until the data is loaded from the API.
When the page first loads it should check if the hasSession
cookie exists? If it doesn't then it shouldn't make any API calls, and should redirect immediately login.
How would I know that I can invoke ajax calls and succeed without making a test call?
You should just assume you have a session ss-id
cookie if you have the hasSession
cookie as you must have logged in successfully to get it. So make you call for the page data. If you get data back from the call and not a 401 exception then populate the form, and display it by altering the CSS.
If you got a 401 redirect to the login screen, and delete the hasSession
cookie. The user won't have seen a blank unpopulated form because the CSS prevented this. They get a loading indicator while waiting, a perfectly reasonable state.
The 401 Authorization error should only occur once, and redirect to login, and that shouldn't even happen if your hasSession
and the ss-id
cookie expiration remain in sync.
I am just confused why you are trying to change the ServiceStack attributes now, subclassing [Authorize]
. You shouldn't need to change the behaviour of the API.
Upvotes: 2