【问题标题】:Two questions about MVC, and Identity关于 MVC 和 Identity 的两个问题
【发布时间】:2015-05-31 05:39:15
【问题描述】:

我对身份和 MVC 非常陌生,我正在尝试创建一个 MVC 应用程序作为我的第一个项目之一。

我已经能够关注 few tutorials 并已成功向我的 ApplicationUser 中添加了其他属性:IdentityUser 类

public class ApplicationUser
    : IdentityUser<string, ApplicationUserLogin,
    ApplicationUserRole, ApplicationUserClaim>
{
    [Required]
    [Display(Name = "UserName")]
    [StringLength(50)]
    public string Handle { get; set; }

    [StringLength(100, ErrorMessage = "Your {0} can be at most {1} characters long.")]
    [Display(Name = "First Name")]
    public string FirstName { get; set; }

    [StringLength(100, ErrorMessage = "Your {0} can be at most {1} characters long.")]
    [Display(Name = "Last Name")]
    public string LastName { get; set; }

    [Required]
    [Display(Name = "User Creation Date")]
    public DateTime UserCreationDate { get; set; }

    public ApplicationUser()
    {
        this.Id = Guid.NewGuid().ToString();

        // Add any custom User properties/code here
    }

我的问题是:

  1. 我看到电子邮件在 App_Start.IdentityConfig.cs 中设置为需要唯一电子邮件的位置,有没有办法将其设置为需要像 Handle 这样的唯一自定义属性?

        var manager = new ApplicationUserManager(new UserStore<ApplicationUser, ApplicationRole, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context.Get<ApplicationDbContext>()));
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
    
  2. 在 Views.Shared._LoginPartial.cshtml 的部分视图中,它显示了使用 User.Identity.GetUserName() 登录应用程序的人的用户名/电子邮件是否有一种方法可以引用我的自定义属性之一而不是这样作为名字还是句柄?

    @using Microsoft.AspNet.Identity
    
    @if (Request.IsAuthenticated)
    {
        using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
        {
        @Html.AntiForgeryToken()
    
        <ul class="nav navbar-nav navbar-right">
            <li>
                @Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
            </li>
            <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
        </ul>
        }
    }
    else
    {
        <ul class="nav navbar-nav navbar-right">
            <li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
            <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
        </ul>
    }
    

【问题讨论】:

    标签: c# razor asp.net-mvc-5 asp.net-identity-2


    【解决方案1】:

    这里已经介绍了实现自定义UserValidatorHow can customize Asp.net Identity 2 username already taken validation message?

    不要为每个页面请求访问数据库以显示句柄,而是在登录期间添加声明。

    定义您自己的声明:

    public static class CustomClaimTypes
    {
        public const string Handle = "http://schemas.xmlsoap.org/ws/2014/03/mystuff/claims/handle";
    }
    

    在登录期间,设置声明:

    private async Task SignInAsync(ApplicationUser user, bool isPersistent, string password = null)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    
        var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
    
        //Get the handle and add the claim to the identity.
        var handle = GetTheHandle();
        identity.AddClaim(new Claim(CustomClaimTypes.Handle, handle);
    
        AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
    }
    

    然后,通过扩展方法你可以像GetUserName()一样读出它:

    public static class IdentityExtensions
    {
        public static string GetHandle(this IIdentity identity)
        {
            if (identity == null)
                return null;
    
            return (identity as ClaimsIdentity).FirstOrNull(CustomClaimTypes.Handle);
        }
    
        internal static string FirstOrNull(this ClaimsIdentity identity, string claimType)
        {
            var val = identity.FindFirst(claimType);
    
            return val == null ? null : val.Value;
        }
    }
    

    最后,在你看来:

    @User.Identity.GetHandle()
    

    【讨论】:

    • 你为什么要告诉我将句柄设置为一个 URL?我希望它成为我的 ApplicationUser 类 [Required] [Display(Name = "UserName")] [StringLength(50)] public string Handle { get; set; } 中的自定义用户名字段设置我这样做是为了绕过 Identity 2.0 中链接的用户名/电子邮件,每次我试图打破这个链接时,我都会得到 Invalid login attempt.
    • 我还尝试实现第一个问题中提到的 Stack Overflow 文章。 How can customize Asp.net Identity 2 username already taken validation message?。我提到了资源。当我实现时,我得到'Microsoft.AspNet.Identity.Resources' is inaccessible due to its protection level 我明白,因为 Microsoft.AspNet.Identity.Resources 被标记为受保护的内部而不是公共,所以我真的不明白他是如何在他的代码中使用它的。
    • @shaun 只是为了澄清,这不是将句柄设置为 URL。相反,URL 是声明类型标识符,如果您仔细查看 SignInAsync 方法,我们正在创建一个使用 URL 作为声明类型的 Claim 实例。在此处查看标准声明类型:msdn.microsoft.com/en-us/library/…
    【解决方案2】:

    1) 我会让你自己的 UserValidator 继承自微软的 UserValidator 并处理你的额外字段。

    更新:

    2)您可以制作自己的扩展方法来获取您添加的额外字段。

    public static string GetSomething(this IIdentity identity)
    {
        if (identity.IsAuthenticated)
        {
            var userStore = new UserStore<ApplicationUser>(new Context());
            var manager = new UserManager<ApplicationUser>(userStore);
            var currentUser = manager.FindById(identity.GetUserId());
            return something = currentUser.something;                
        }
        return null;
    }
    

    【讨论】:

    • IIdentity 类不会转换为 ApplicationUser。这将引发运行时异常。
    • 这也是我得到的。 Unable to cast object of type 'System.Security.Claims.ClaimsIdentity' to type 'Foo.Models.ApplicationUser'。 ApplicationUser 是接口 IUser 而不是 IIdentity。到目前为止,我还没有看到将两者联系起来。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 2013-02-20
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    相关资源
    最近更新 更多