This is a migrated thread and some comments may be shown as answers.

Login / Logout scenario in SPA

1 Answer 374 Views
SPA
This is a migrated thread and some comments may be shown as answers.
Jacques
Top achievements
Rank 1
Jacques asked on 24 Feb 2015, 07:22 PM
I have a single page app built with KendoUI javascript framework from Telerik. The pages are loaded from a client router (samples and docs here) and javascript modules are added with RequireJS. I added some authentication mechanism based on the WIF Session Authentication Module (SAM) based on this article from Dominick Baier : http://leastprivilege.com/2012/02/09/replacing-asp-net-forms-authentication-with-wif-session-authentication-for-the-better/ It works very similar to the Forms authentication since I am just adding a authentication tag with a form url like this :

<authentication mode="None">
    <forms loginUrl="~/#/Public/Accueil" timeout="90" slidingExpiration="true" requireSSL="true" />
</authentication>


It works fine under a normal .NET MVC4 scenario, but doesn't quite work as well when in a SPA with javascript routing. The view is displayed when the user is not logged, but nothing happens when I click on "Log in" button because. Does anyone have a clue about what I should do to keep the sync between server and client whenever a redirection on the login page occurs on the server ?

When you use a authentication tag and specify a form url, a 302 response is sent to the client every time a page that needs authorization is called without the auth cookie. The URL to wich the browser is redirected then is the one specified in the web.config under the authentication tag (like in my question it is "<base_url>/#/Public/Acceuil") and the url requested originaly requested is appended as parameter like this : "<base_url>/#/Public/Acceuil?RETURNURL=Private/Profile>". The browser then make a GET request to this new url and gets a 200 with the login view. That works just fine. The problem is that the client methods are in a separate js file that is normally loaded via the client Kendo Router using RequireJS :

router-config.js :

define(['jquery', 'lib/pubsub'],
function ($, pubsub) {
 
// Index
var publicAccueil =
    url: "/Public/Accueil",
    activate: function () {
        var that = this;
        require(['app/Public/Accueil'], function () { renderView(that); });
     },
    html: null
};
 
// MDPOublie
var publicMDPOublie =
{
    url: "/Public/MDPOublie",
    activate: function () {
        var that = this;
        require(['app/Public/MDPOublie'], function () { renderView(that); });
     },
    html: null
};
 
// Profil
var privateProfile =
{
    url: "/Private/Profile",
    activate: function () {
        var that = this;
        require(['app/Private/Profile'], function () { renderView(that); });
    },
    html: null
};
 
var renderView = function(view, id, params) {
        $.publish("viewActivated", [ view, id, params ]);
};
 
return {
        publicAccueil: publicAccueil,
        publicMDPOublie: publicMDPOublie,
        privateProfile: privateProfile,
};
});




Then, in the router file, the route are registered to call the "activate" fonction defined in the config object "routeConfig.privateProfile" for the route, that's what loads the Accueil.js file located unde "app/Public/".

router.js :

define([
'jquery',
'kendo',
'app/route-config',
'app/Code52'
], function ($, kendo, routeConfig, Code52) {
 
var router = new kendo.Router({
routeMissing: function (e) { alert("Route not defined : " + e.url); },
change: function (e) {
 
kendo.destroy("#content");
}
});
 
//Default route
router.route("/", function() {
var cheminUrl = window.location.pathname;
 
if (cheminUrl === "/") {
router.navigate(routeConfig.publicAccueil.url);
}
});
 
router.route(routeConfig.publicAccueil.url, function () { routeConfig.publicAccueil.activate(); });
router.route(routeConfig.publicMDPOublie.url, function () { routeConfig.publicMDPOublie.activate(); });
router.route(routeConfig.privateProfile.url, function () { routeConfig.privateProfile.activate(); });
 
$.subscribe("viewActivated", function (view, id, params) {
        //If the view is not in local cache, we load it from server
        if (view.html === null || view.html === "") {
            $.ajax({
                url: view.url + (id !== undefined ? "/" + id : "")
            }).done(function (r) {
               
                //Once loaded, we cache it
                view.html = r.data;
                //Render the view by injecting innerHtml property
                $("#content").html(view.html);
                //Event published just for each script to have a place to init
                if (view.html !== "")
                    id !== undefined ? $.publish(view.url, [id, params]) : $.publish(view.url, [params]);
                
            })
            .fail(function (jqXHR, textStatus) {
                alert("Request failed: " + textStatus);
            });
        } else { //If the view was already cached, we load thie cached version
            $("#content").html(view.html);
            id !== undefined ? $.publish(view.url, [id, params]) : $.publish(view.url, [params]);
        }
    });

    return {
        router: router
    };
});

The other obvious problem here is when I disconnect by calling a Disconnect method. I just flush the auth cookie then, but all the "private" pages are still in cache, which means they'll be displayed if you hit the corresponding route.

So, is there a sample or tutorial somewhere on how to manage this kind of "login / logout" scenarios ?

1 Answer, 1 is accepted

Sort by
0
Petyo
Telerik team
answered on 26 Feb 2015, 01:12 PM
Hi Jacques,

the simplest thing you can do upon logout is to refresh the page, thus removing all sensitive data loaded. 

Regards,
Petyo
Telerik
 
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
 
Tags
SPA
Asked by
Jacques
Top achievements
Rank 1
Answers by
Petyo
Telerik team
Share this question
or