如何使用AspNet.Identity在Asp.Net MVC5 RTM版本中登录/认证用户?

49

我一直在使用MVC5、EF6和VS 2013开发Web应用程序。

发布RC版本后,我花了一些时间升级。感谢所有伟大的帖子,例如:分离Microsoft.AspNet.Identity.*从5.0.0-beta2更新到5.0.0-rc1的Asp.net MVC

出于我的无限智慧,我决定转移到@Hao Kung在这里发布的RTM版本: 如何获得即将推出的Asp.Net Identity更改的早期访问权限?。我想我会省去麻烦,不会太落后,当我们最终收到RTM构建时。

这要么是一场噩梦,要么是我完全忽略了某些东西(或两者都有),因为我无法理解使用RC1的基本任务。

虽然看起来我通过控制器 (在Asp.Net Identity RTM版本中,Microsoft.AspNet.Identity.Owin.AuthenticationManager在哪里?) 登录用户…但是我调用SignIn后,我的WindowsIdentity始终为空且未经过身份验证。用户和ClaimsIdentity对象被正确填充。

这里是我正在调用的操作方法(将属性移动到本地变量以保证完整性):

[HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
public virtual async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid) {
        var userManager = new UserManager<EtdsUser>(new UserStore<EtdsUser>(new EtdsContext()));
        var user = userManager.Find(model.UserName, model.Password);
        if (user != null) {
            var authenticationManager = HttpContext.GetOwinContext().Authentication;
            authenticationManager.SignOut(new[] {DefaultAuthenticationTypes.ApplicationCookie, DefaultAuthenticationTypes.ExternalCookie, DefaultAuthenticationTypes.ExternalBearer});
            var claimsIdentity = await userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = model.RememberMe}, claimsIdentity);
            return RedirectToLocal(returnUrl);
        }
    }
    ModelState.AddModelError("", "The user name or password provided is incorrect.");
    return View(model);
}

(旁注:此时我不需要登录外部用户。)

有什么建议吗?

-或者-

我应该撤销所有更改,等到VS 2013发布吗?


更新,重构代码以使其更接近@HaoKung的原始回复。但是,我仍然没有获得有效的用户身份。我认为我的AuthenticationManager没有被正确分配?

现在定义的AuthenticationManager如下:

public IAuthenticationManager AuthenticationManager { get { return HttpContext.GetOwinContext().Authentication; } }

SignInAsync现在是一个单独的方法:

private async Task SignInAsync(EtdsUser user, bool isPersistent)
{
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    var claimsIdentity = await _userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
    AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent}, claimsIdentity);
}

在“SignOut”之后,调试器显示:

AuthenticationManager.User.Identity
{System.Security.Principal.WindowsIdentity}
    [System.Security.Principal.WindowsIdentity]: {System.Security.Principal.WindowsIdentity}
    AuthenticationType: ""
    IsAuthenticated: false
    Name: ""

“claimsIdentity” 然后是:

claimsIdentity
{System.Security.Claims.ClaimsIdentity}
    Actor: null
    AuthenticationType: "ApplicationCookie"
    BootstrapContext: null
    Claims: {System.Security.Claims.ClaimsIdentity.get_Claims}
    IsAuthenticated: true
    Label: null
    Name: "alon"
    NameClaimType: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
    RoleClaimType: "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"

"SignIn"并没有改变任何东西:

AuthenticationManager.User.Identity
{System.Security.Principal.WindowsIdentity}
    [System.Security.Principal.WindowsIdentity]: {System.Security.Principal.WindowsIdentity}
    AuthenticationType: ""
    IsAuthenticated: false
    Name: ""

仍没有身份验证,但似乎没有抛出任何错误。


根据@Hao Kung的回答,将StartUp.Auth.cs从以下内容更改为:

var authOptions = new CookieAuthenticationOptions { ExpireTimeSpan = TimeSpan.FromHours(4.0)};
app.UseCookieAuthentication(authOptions);

收件人:

var authOptions = new CookieAuthenticationOptions {
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    ExpireTimeSpan = TimeSpan.FromHours(4.0)
}; ...

有一个接口... Microsoft.Owin.Security.IAuthenticationManager - user2315985
HttpContext.GetOwinContext().Authentication 不是返回 IAuthenticationManager 的实现吗?至少我是这么认为的,但我可能漏掉了什么。 - ACG
1个回答

41

以下是RTM中登录的基本样式(代码来自ASPNET Identity示例代码):

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            var user = await UserManager.FindAsync(model.UserName, model.Password);
            if (user != null)
            {
                await SignInAsync(user, model.RememberMe);
                return RedirectToLocal(returnUrl);
            }
            else
            {
                ModelState.AddModelError("", "Invalid username or password.");
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

    private async Task SignInAsync(ApplicationUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
        AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
    }

编辑:您需要在Startup.Auth.cs中做如下更改:

        app.UseCookieAuthentication(new CookieAuthenticationOptions {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });

太棒了,谢谢!只是好奇,我的“userManager”和“authenticationManager”的实例化看起来正确吗?根据您之前的帖子,我修改了我的登录方法,所以希望我走在正确的道路上。 - ACG
请看我编辑后的问题,其中包含了更多的细节。 - ACG
2
我在startup.auth.cs中也添加了你可能需要的更改。 - Hao Kung
就是这样。基本上相当烦人;-)只需要添加1/2行即可。谢谢! - ACG
为什么HttpContext.GetOwinContext()没有可用的GetOwinContext()方法?您有任何想法吗? - user2315985
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接