Asp.Net身份验证:无需电子邮件保存用户

40

我想保存没有电子邮件的用户,就像这样:

var user = new ApplicationUser { UserName = model.Name };
var result = await UserManager.CreateAsync(user);

但是我遇到了“电子邮件不能为空”的错误。有解决方法吗?还是说这是不可能的?


我有完全相同的问题,尽管“邮件”已提供,但“结果”始终返回null,但是操作成功了。这个问题有解决方案吗? - Dev
7个回答

91

我知道这是老问题,但我不同意已接受的答案,因为该问题标记为asp.net-identity-2。为了未来读者的利益,ASP.NET Identity 2.0有一个非常简单的解决方案:

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    ...snip...
    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
    {
        var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            // This disables the validation check on email addresses
            RequireUniqueEmail = false
        };
        ...snip...
    }
}

UserValidator<TUser> 中,Task<IdentityResult> ValidateAsync(T item) 的实现会检查此标志,并确定是否应运行电子邮件验证:
if (this.RequireUniqueEmail)
{
    await this.ValidateEmail(item, list);
}

如果您想保存没有电子邮件地址的用户,应该这样做。

注意:仅在不收集电子邮件地址时使用。如果您想收集和验证电子邮件地址,但在注册过程中使其可选,则应使用自定义IIdentityValidator


3
你的头像很赞!当然,对问题的回答也是正确的!:) - Mike Devenney

34

ASP身份认证2.2可以在 App_Start\IdentityConfig.cs 中设置。

    manager.UserValidator = new UserValidator<ApplicationUser>(manager)
    {
        AllowOnlyAlphanumericUserNames = false,
        RequireUniqueEmail = false
    };

11

在启动文件中,您可以通过访问IdentityOptions配置来禁用RequireUniqueEmail。另外,在此处您还可以更改密码的复杂度、锁定等设置...

  services.Configure<IdentityOptions>(x =>
        {
            x.User.RequireUniqueEmail = false;

            //x.Password.RequireUppercase = false; => other condition for identity

        });

您应该使用Microsoft.AspNetCore.Identity,文档地址在此处

感谢@PBO,您也可以像下面这样更改身份选项

 services.AddDefaultIdentity<IdentityUser>(
            options=> { 
                options.SignIn.RequireConfirmedAccount = false;
                options.User.RequireUniqueEmail = false;
                options.Password.RequireUppercase = false;
            })
            .AddEntityFrameworkStores<BookShopDbContext>();

1
你可以在 services.AddDefaultIdentity 中访问相同的功能。 - PBo

9

身份验证依赖于电子邮件作为重置用户密码的方式。

然而,忽略电子邮件并不简单,但是可以通过实现Microsoft.AspNet.Identity.IIdentityValidator接口来忽略缺少的电子邮件:

namespace Microsoft.AspNet.Identity
{
  /// <summary>
  /// Used to validate an item
  /// 
  /// </summary>
  /// <typeparam name="T"/>
  public interface IIdentityValidator<in T>
  {
    /// <summary>
    /// Validate the item
    /// 
    /// </summary>
    /// <param name="item"/>
    /// <returns/>
    Task<IdentityResult> ValidateAsync(T item);
  }
}

然后在ApplicationUserManager中将您自己的实现分配给属性UserValidator

如果您确实需要此功能,可以通过反编译Microsoft.AspNet.Identity.UserValidator类并查看现有源代码并删除对电子邮件的检查来获取UserValidator的原始源代码。

但是,我不确定框架的其余部分如何对用户缺少电子邮件做出反应。可能会在其他操作中收到异常。


6
如果有人仍然在解决这个问题...
请设置 options.User.RequireUniqueEmail=true,创建一个自定义用户验证器并在注册 Identity 之前将其注册。这样将使电子邮件地址变成可选,但如果输入了电子邮件,仍会要求它是唯一的。
ConfigureServices(IServiceCollection services) 中实现以上操作:
services.AddTransient<IUserValidator<ApplicationUser>, OptionalEmailUserValidator<MonotypeIdentityUser>>();
services.AddIdentity(...);

自定义用户验证器类:

public class OptionalEmailUserValidator<TUser> : UserValidator<TUser> where TUser : class
{
    public OptionalEmailUserValidator(IdentityErrorDescriber errors = null) : base(errors)
    {
    }

    public override async Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user)
    {
        var result = await base.ValidateAsync(manager, user);
        
        if(!result.Succeeded && String.IsNullOrWhiteSpace(await manager.GetEmailAsync(user)))
        {
            var errors = result.Errors.Where(e => e.Code != "InvalidEmail");

            result = errors.Count() > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
        }           

        return result;
    }
}

2
很棒的答案,你也可以只使用services.AddIdentity().AddUserValidator<OptionalEmailUserValidator<ApplicationUser>>()来注入一行代码。 - Babatunde Ahmed

3

您可以通过编辑位于 App_Start 文件夹中的 Identity 文件,并将 RequireUniqueEmail 值更改为 False 来创建无需电子邮件的用户帐户,以避免电子邮件验证器。

  manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = false,
        };

`


0

实际上有更好的方法。只在需要忽略验证时更改验证,然后在完成后恢复它。(在这种情况下不要使用异步,因为可能需要另一个线程来更新(?))

// first create/update the identity!!! 
user.PasswordHash = UserManager.PasswordHasher.HashPassword(model.Password); //hash and update directly

// alter
UserManager.UserValidator = new UserValidator<StoreUser>(UserManager)
{
    AllowOnlyAlphanumericUserNames = false,
    RequireUniqueEmail = false
};

var result = UserManager.Update(user);

// restore... 
UserManager.UserValidator = new UserValidator<StoreUser>(UserManager)
{
    AllowOnlyAlphanumericUserNames = false,
    RequireUniqueEmail = true
};

1
这是一个非常糟糕的想法。如果两个人同时更新他们的用户,会发生什么?竞态条件就是这样。为什么不像其他人建议的那样,在启动时只设置一次呢? - Liam
如果我想将AspNetUsers中现有的电子邮件及其相关字段存储到单独的表中,该怎么办?电话字段也一样? - muybn
@muybn,我成功地将电话号码和电子邮件地址分离到一个AccountContact表中。这是一项艰巨的工作,除非你有特定的原因去做它,否则这是浪费时间。我遇到了很多错误,需要花费很多时间查看源代码才能理解发生了什么。最初我也删除了用户名,但为了让我的项目继续进行(我根据客户提供的信息填写电话号码或电子邮件),我恢复了它。 - PBo

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