ServiceStack-电子邮件确认

时间:2019-05-07 02:17:45

标签: authentication asp.net-core .net-core authorization servicestack

我正在尝试在ServiceStack中实施电子邮件确认。我花了5天的时间试图弄清所有身份验证机制,而且我必须说这非常复杂。该代码不容易阅读。

例如,我很难知道:

  • 为什么叫IAuthProvider.OnAuthenticated?有时似乎是可选的。
  • 为什么叫IAuthSession.PopulateSession?与IAuthProvider.PopulateSession有何不同?
  • 为什么叫IRequest.SaveSession
  • 什么是IAuthTokens?为什么它们在某个时候合并?是因为可以通过许多不同的提供程序对用户进行身份验证,并且我们需要合并IAuthTokens?他们喜欢索赔吗?
  • Session.FromToken仅用于JWT吗?
  • IAuthWithRequest.PreAuthenticateIAuthProvider.Authenticate有何不同?在这两种方法中应该做什么不同?我收集到每个请求都调用PreAuthenticate,而在使用/ auth / {provider}(在这种情况下为/ auth / email)时调用Authenticate。我想念什么吗?

除了这些问题之外,为了解决该问题,我尝试了两种方法:

  1. 实现EmailConfirmationAuthProvider

    1. 通过添加UserAuth字段,以CustomUserAuth覆盖默认bool EmailConfirmed {get;set;}

    2. 用户注册后,将使用秘密令牌向用户发送电子邮件。该令牌存储在某处。

    3. 当用户单击链接(https://blabla.com/auth/email?token=abcdef)时,如果令牌有效且未过期,则EmailConfirmationAuthProvider.PreAuthenticate会将CustomUserAuth.EmailConfirmed标记为true。令牌已删除,因此无法再次使用该令牌进行身份验证。

    4. 我不知道如何将EmailConfirmed = true添加到会话中,也不知道如何在后续登录时添加它。而且我不知道如何不妨碍其他身份验证机制。

  2. 实施EmailConfirmationService

    1. (与1.1和1.2相同的步骤)

    2. 当用户单击链接(https://blabla.com/email-confirmation?token=abcdef)时,如果令牌有效且未过期,则EmailConfirmationService会将CustomUserAuth.EmailConfirmed标记为true。令牌已删除,无法重复使用同一令牌。

    3. 我不知道如何从CustomUserAuth重新填充会话,尤其是如果用户已经通过JWT令牌进行了身份验证(如果JwtAuthProvider是{ {1}})。我想找到一种为该用户的所有后续登录向会话添加EmailConfirmed标志的方法。我没有找到如何“修改” JWT令牌的方法(通过添加EmailConfirmed = true),并将其作为cookie发送回去,这样就不必检查每个请求是否都确认了电子邮件。

      < / li>

基本上,我想将所有标记为AuthFeature.AuthProviders的服务的访问权限限制为已确认电子邮件地址的用户。如果我错了,请纠正我,但这仅适用于使用凭据注册的用户(如果用户使用[Authenticate]登录,则电子邮件确认不适用。还是?)

该规则的例外是某些服务(标记为属性GoogleAuthProvider),这些服务允许用户将确认电子邮件重新发送到其地址(例如,他们输入了错误的电子邮件地址)。 [AllowUnconfirmedEmail]可以允许经过身份验证的用户将新的确认发送到新地址。单击该确认电子邮件后,EmailConfirmationService将使用新地址进行更新。

1 个答案:

答案 0 :(得分:2)

请参考ServiceStack Authentication Docs中的高级图以说明session based Auth ProvidersIAuthWithRequest Auth Providers的工作方式。

其中许多问题是内部实现细节,它们的不同身份验证提供商在需要它们时会调用它们。您可以添加自定义逻辑的用户可覆盖事件在Session and Auth Events中发布。

Car [0.99] 4 wheel drive [0.03] color red [0.009] IAuthWithRequest Auth Providers调用,它们对每个请求(例如API KeyJWT Auth Provider)进行身份验证。通过PreAuthenticate()提供程序进行身份验证时,将调用Authenticate()

实施电子邮件确认

实施需要确认电子邮件的用户的最简单方法可能是实施Custom UserSession Validation,例如:

/auth

因此,仅当用户具有确认的电子邮件地址时,它才允许身份验证。

有关如何将自定义public class CustomUserSession : AuthUserSession { public override IHttpResult Validate(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo) { using (var db = HostContext.AppHost.GetDbConnection(authService.Request)) { var userAuthId = int.Parse(session.UserAuthId); if (!db.Exists<CustomUserAuth>(x => x.Id == userAuthId && x.EmailConfirmed)) return HttpError.Conflict($"Email not confirmed") as IHttpResult; } return null; } } 表与其他元数据(例如UserAuth)一起使用的信息,请参见Extending UserAuth Tables

您的电子邮件服务将成为接受诸如EmailConfirmed(在Guid中或在单独的表中)这样的随机字符串的服务,该字符串引用已确认其电子邮件的用户。另外,电子邮件中的链接可以仅再次包含该电子邮件,在这种情况下,您可以将其与CustomUserAuth表的Email字段中的现有电子邮件进行匹配。

如果您随后要在同一请求中对用户进行身份验证,则可以通过以下方式配置CustomUserAuth来允许password-less Authenticated requests

CredentialsAuthProvider

然后,您将只使用用户名在同一“处理中”请求中进行身份验证:

new CredentialsAuthProvider {
    SkipPasswordVerificationForInProcessRequests = true,
}

您可以使用UseTokenCookie to authenticate the User with a HTTP Only JWT Session,尽管不需要使用JWT。

此解决方案不是必需的,但是您可以通过implementing CreatePayloadFilter向JWT令牌添加其他信息,并可以通过实现using (var service = base.ResolveService<AuthenticateService>()) //In Process { return service.Post(new Authenticate { provider = AuthenticateService.CredentialsProvider, UserName = request.UserName, UseTokenCookie = true, // if using JWT }); } 在用户会话中填充这些其他元数据。

  

我不知道如何在会话中添加EmailConfirmed = true

您可以通过在自定义PopulateSessionFilter上实现OnAuthenticated()来填充UserSession。

  

基本上,我想限制已确认电子邮件地址的用户访问所有标有[验证]的服务。

如上所述,在您的自定义AuthUserSession中覆盖AuthUserSession将确保只有具有确认电子邮件的用户才能进行身份验证。

  

此规则的例外是某些服务

您没有通过“部分认证的用户”的概念(或者已将“认证的用户会话”附加到请求或缓存),或者没有。只有在他们确认电子邮件后,我才允许身份验证;如果他们确认要将电子邮件更改为他们的提议电子邮件,则仅更新其确认电子邮件。