KnockoutJS + WebAPI 2令牌身份验证 - 维护登录状态,直到令牌过期

时间:2017-02-13 13:00:22

标签: authentication model-view-controller asp.net-web-api knockout.js bearer-token

我对基于令牌的身份验证相当新,我遇到了登录后如何维护登录状态的问题。 我想创建一个SPA网站,我正在使用Knockoutjs作为我的前端,而SammyJS则用于路由和更改视图。 登录并获取令牌后,我将其存储在localStorage中,并将用户名设置为我正在显示的observable。

我的问题是,在我关闭标签页或浏览器并返回该站点后,令牌位于localStorage中,但我看不到用户已登录。 我想保持登录状态,直到令牌过期。我的问题是,当我进入网站以保持该用户的登录状态时,我应该如何处理来自localStorage的令牌?

我是否需要在启动类中创建某些内容或检查该用户是否存在于数据库中?

提前致谢!

这是我的代码:

StartupAuth.cs

    [assembly: OwinStartup(typeof(EventHub.PL.WebUI.Startup))] namespace EventHub.PL.WebUI {
        public partial class Startup
        {
            public static OAuthAuthorizationServerOptions OAuthOptions { get;private set; }
            public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
            public const string TokenEndpointPath = "/api/token";
            public static string PublicClientId { get; private set; }
            // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
            public void ConfigureAuth(IAppBuilder app)
            {
                // Configure the db context and user manager to use a single instance per request
                app.CreatePerOwinContext(ApplicationDbContext.Create);
                app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
                // Enable the application to use a cookie to store information for the signed in user
                // and to use a cookie to temporarily store information about a user logging in with a third party login provider
                app.UseCookieAuthentication(new CookieAuthenticationOptions());
                app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
                OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
                // Configure the application for OAuth based flow
                PublicClientId = "self";
                OAuthOptions = new OAuthAuthorizationServerOptions
                {
                    TokenEndpointPath = new PathString(TokenEndpointPath),
                    Provider = new ApplicationOAuthProvider(PublicClientId),
                    //AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
                    // In production mode set AllowInsecureHttp = false
                    AllowInsecureHttp = true
                };
                // Enable the application to use bearer tokens to authenticate users
                //app.UseOAuthBearerTokens( OAuthOptions );
                app.UseOAuthAuthorizationServer(OAuthOptions);
                app.UseOAuthBearerAuthentication(OAuthBearerOptions); 
            }
         }

AccountController.cs

[HttpPost]
        [AllowAnonymous]
        [Route("Login")]
        public async Task<IHttpActionResult> Login(LoginUser model)
        {
            var request = HttpContext.Current.Request;
            var tokenServiceUrl = request.Url.GetLeftPart(UriPartial.Authority) + request.ApplicationPath + "/api/Token";
            using (var client = new HttpClient())
            {
                var requestParams = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>("grant_type", "password"),
                    new KeyValuePair<string, string>("username", model.Email),
                    new KeyValuePair<string, string>("password", model.Password)
                };
                var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams);
                var tokenServiceResponse = await client.PostAsync(tokenServiceUrl, requestParamsFormUrlEncoded);
                var responseString = await tokenServiceResponse.Content.ReadAsStringAsync();
                var json = JsonConvert.DeserializeObject<TokenResponse>(responseString);
                var responseCode = tokenServiceResponse.StatusCode;
                if (responseCode == HttpStatusCode.OK)
                {
                    RegisterUser user = userRepository.GetNameById(json.Id);
                    var data = new
                    {
                        status = "success",
                        json.access_token,
                        user.Lastname
                    };
                    return Json(data);
                }
                return Json(new { status = "failed" });
            }
        }

这是 KO 部分:

var LoginApp = function () {
    var instance = this;
    instance.mainViewModel = new MainViewModel();
    instance.loginViewModel = new LoginViewModel();
    instance.loginRepository = new LoginRepository();
    instance.loginViewModel.signIn = function() {
        $('.loader-header').show();
        var postData = {
            email: instance.loginViewModel.email(),
            password: instance.loginViewModel.password
        }
        instance.loginRepository.SignIn(SignInSuccess, postData);
    };
    instance.SignInSuccess = function(response) {
        if (response.status === 'success') {
            instance.mainViewModel.username(response.Lastname);
            instance.mainViewModel.isVisible(true);
            var userData = {
                token: response.access_token,
                username: response.Lastname
            };
            localStorage.setItem('AuthorizationData', JSON.stringify(userData));
            $('.loader-header').hide();
            dialog.close();
        } else {
            $('.loader-header').hide();
        }
    };
    instance.init = function () {
        ko.applyBindings(instance.loginViewModel, document.getElementById("signin-form"));
        ko.applyBindings(instance.mainViewModel, document.getElementById("main-wrapper"));
    }
    instance.init();
}
$(document).ready(function () {
    var loginApp = LoginApp();
});

更新

这是我的路由

var appRoot = root;

(function ($) {
    var app = $.sammy('#page', function () {
        this.get('#/home', function (context) {
            document.title = 'Home - ' + title;
            var url = getUrlFromHash(context.path);
            loadView(url, new MainViewModel(), MainApp);
            //context.load(url).swap();
        });
        this.get('#/about', function (context) {
            var url = getUrlFromHash(context.path);
            loadView(url, new AboutViewModel(), AboutApp);
        });
        this.get('#/manage', function (context) {
            var url = getUrlFromHash(context.path);
            loadView(url, new AboutViewModel(), AboutApp);
        });
    });
    $(function () {
        app.run('#/home');
    });
})(jQuery);
function loadView(url, viewModel, callback) {
    $.get(url, function (response) {
        var $container = $('#page');
        //var $view = $('#page').html(response);
        $container.html(response);
        callback();
    });
}
function getUrlFromHash(hash) {
    var url = hash.replace('#/', '');
    if (url === appRoot)
        url = 'home';
    return url;
}

1 个答案:

答案 0 :(得分:0)

现在,您所做的只是将用户的凭据存储在localStorage中,而不是使用它们来执行授权。另一种方法是使用Sammy.OAuth2插件(你可以找到它here)。

您可以定义路由以进行如下身份验证:

app.post("#/oauth/login", function(context) {
    this.load('http://yourwebsite/login',
        {
            cache: false, 
            type: 'post',
            data: {
                email: $("input[name=email]").val(), 
                password: $("input[name=password]").val()
            }
        })
        .then(function(content) {
            if(content != false){
                if(app.getAccessToken() == null){
                    app.setAccessToken(token());
                }
            }else{
                app.trigger("oauth.denied");
                return false;
            }
        });
});

在“受保护”路线中,您可以检查用户是否已经登录:

app.get("#/profile", function(context) {

    if(app.getAccessToken() != null)
        context.render('view/profile.template');
    else
        this.requireOAuth();

});

必须修改此示例以根据您的方案填充令牌。这是关于Sammy.Oath2的完整教程。

相关问题