C# 关于MVC和身份的两个问题

C# 关于MVC和身份的两个问题,c#,razor,asp.net-mvc-5,asp.net-identity-2,C#,Razor,Asp.net Mvc 5,Asp.net Identity 2,我对身份和MVC非常陌生,我正在尝试创建一个MVC应用程序,作为我的第一个项目之一 我已经能够遵循并成功地向ApplicationUser:IdentityUser类添加了其他属性 public class ApplicationUser : IdentityUser<string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim> { [Required] [Displa

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

我已经能够遵循并成功地向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
    }
公共类应用程序用户
:IdentityUser
{
[必需]
[显示(Name=“UserName”)]
[长度(50)]
公共字符串句柄{get;set;}
[StringLength(100,ErrorMessage=“您的{0}最多可以有{1}个字符长。”)]
[显示(Name=“First Name”)]
公共字符串名{get;set;}
[StringLength(100,ErrorMessage=“您的{0}最多可以有{1}个字符长。”)]
[显示(Name=“Last Name”)]
公共字符串LastName{get;set;}
[必需]
[显示(Name=“用户创建日期”)]
公共日期时间UserCreationDate{get;set;}
公共应用程序用户()
{
this.Id=Guid.NewGuid().ToString();
//在此处添加任何自定义用户属性/代码
}
我的问题是:

  • 我知道在App_Start.IdentityConfig.cs中,电子邮件被设置为需要唯一的电子邮件,是否有方法将其设置为需要唯一的自定义属性(如句柄)

        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
        };
    
    var-manager=newapplicationusermanager(newuserstore
  • } } 其他的 {
    • @ActionLink(“Register”、“Register”、“Account”、routeValue:null、htmlAttributes:new{id=“registerLink”})
    • @ActionLink(“登录”、“登录”、“帐户”、routeValue:null、htmlAttributes:new{id=“loginLink”})
    }
    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;
    }
    
    公共静态字符串GetSomething(此IIdentity标识)
    {
    如果(身份验证)
    {
    var userStore=newuserstore(newcontext());
    var-manager=新的UserManager(userStore);
    var currentUser=manager.FindById(identity.GetUserId());
    return something=currentUser.something;
    }
    返回null;
    }
    
    实现自定义
    用户验证程序
    已在此处介绍:

    与其为每个页面请求点击数据库来显示句柄,不如在登录期间添加声明

    定义您自己的索赔:

    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()
    相同的方式读取它:

    最后,你认为:

    @User.Identity.GetHandle()
    

    IIdentity
    类不会强制转换为
    ApplicationUser
    。这将引发运行时异常。这也是我得到的<代码>无法将类型为“System.Security.Claims.ClaimsIdentity”的对象强制转换为类型为“Foo.Models.ApplicationUser”。ApplicationUser是接口IUser而不是IISER。我现在还没有看到链接这两个链接。为什么你要我将句柄设置为URL?我希望它成为我的ApplicationUser类中的自定义用户名字段设置
    [Required][Display(Name=“UserName”)][StringLength(50)]公共字符串句柄{get;set;}
    我这样做是为了绕过Identity 2.0中链接的用户名/电子邮件,每次尝试断开此链接时,我都会得到
    无效的登录尝试。
    我还尝试实现第一个问题中提到的堆栈溢出文章。我提到资源。当我实现时,我得到的
    “Microsoft.AspNet.Identity.Resources”由于其保护级别而无法访问。
    我理解,因为Microsoft.AspNet.Identity.Resources被标记为受保护的内部而不是公共,所以我真的不理解他是如何在他的代码中使用它的。@shaun只是想澄清一下,这不是将句柄设置为URL。相反,URL是声明类型标识符,如果仔细查看
    SignInAsync
    方法,我们将创建一个
    claim
    实例,该实例使用URL作为声明类型。请参见此处的标准索赔类型:
    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()