Durandal login page redirect pattern

后端 未结 2 2193
野性不改
野性不改 2021-02-01 07:58

TL;DR What is a good pattern for requiring a user to login in order to view certain pages in a Durandal Single Page Application (SPA)?

I need a system w

2条回答
  •  死守一世寂寞
    2021-02-01 08:11

    Query-string pattern

    Attempting to implement the "navigate back" method described in my question I have decided against using this method because of the limitations I have described above.

    I have found in practice that a method which works much better is to pass the URL to the page which requires authentication as a query string to the login page, which can then use this to navigate forward to this URL once a user is authenticated.

    Below is an outline of an implementation of this method which I have adopted. I am still keen to learn about any other login patterns that people have adopted for use in Durandal applications however.

    Implementation

    In main.js (or anywhere before router.activate() is called) I still guard the route which requires authentication:

    router.guardRoute = function (instance, instruction) {
        if (user.isAuthenticated()) {
            return true;
        } else {
            if (instance && typeof (instance.preventAnonymous) === "boolean") {
                if (instance.preventAnonymous) {
                    return 'login/' + instruction.fragment;
                }
            }
    
            return true;
        }
    };
    

    In shell.js:

    return {
        router: router,
        activate: function () {
            router.map([
                ...
                { route: 'login', title: '', moduleId: 'viewmodels/login', nav: true },
                { route: 'login/:redirect', title: '', moduleId: 'viewmodels/login', nav: true },
                ...
            ]).buildNavigationModel();
            return router.activate();
        },
        ...
    }
    

    In viewmodels/login.js:

    viewmodel = {
        ...,
        canActivate: function() {
            if (!user.isAuthenticated()) {
                return true;
            }
            return false;
        },
    
        activate: function(redirect) {
            viewmodel.redirect = redirect || "";
        },
        loginUser() {
            ...
            if (user.isAuthenticated()) {
                router.navigate(viewmodel.redirect);
            }
            ...
        },
        ...
    }
    

    Limitation

    One minor negative of this method is the prescense of the page fragment to redirect to upon a succesful login in the application URL query string. If you do not like the prescence of this page fragment in the URL query string, local storage could easily be used instead to store this value. In router.guardRoute one could simple replace the line

    return 'login/' + instruction.fragment;
    

    with

    /* Check for local storage, cf. http://diveintohtml5.info/storage.html */
    if ('localStorage' in window && window['localStorage'] !== null){
        localStorage.setItem("redirect", instruction.fragment);
        return 'login/';
    } else {
        return 'login/' + instruction.fragment;
    }
    

    and our activate method could look like:

    activate: function(redirect) {
        if ('localStorage' in window && window['localStorage'] !== null){
            viewmodel.redirect = localStorage.getItem("redirect");
        } else {
            viewmodel.redirect = redirect || "";
        }
    },
    

提交回复
热议问题