首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ServiceStack -电子邮件确认

ServiceStack -电子邮件确认
EN

Stack Overflow用户
提问于 2019-05-07 02:17:45
回答 1查看 186关注 0票数 2

我正试图在ServiceStack中实现电子邮件确认。我花了5天的时间试图弄清楚所有的认证机制,我必须说,这是非常复杂的。代码不容易读懂。

例如,我很难知道:

  • 为什么叫IAuthProvider.OnAuthenticated?有时候这似乎是可选的。
  • 为什么叫IAuthSession.PopulateSession?它和IAuthProvider.PopulateSession有什么区别?
  • 为什么叫IRequest.SaveSession
  • IAuthTokens是什么?为什么他们会在某个时候被合并?是因为用户可以通过许多不同的提供程序进行身份验证,而我们需要合并IAuthTokens吗?它们像索赔一样吗?
  • Session.FromToken只适用于JWT吗?
  • IAuthWithRequest.PreAuthenticateIAuthProvider.Authenticate有什么不同?在这两种方法中,应该采取什么不同的做法?据我所知,每个请求都会调用PreAuthenticate,并在使用/auth/{provider} (在本例中为/auth/email)时调用身份验证。我是不是遗漏了什么?

撇开这些问题不谈,为了解决问题,我尝试了两种方法:

  1. 实现EmailConfirmationAuthProvider
代码语言:javascript
复制
1. Override the default `UserAuth` with `CustomUserAuth` by adding a `bool EmailConfirmed {get;set;}` field.
2. When user signs up, an email is sent to the user with a secret token. This token is stored somewhere. 
3. When the user clicks on the link ([https://blabla.com/auth/email?token=abcdef](https://blabla.com/auth/email?token=abcdef)), the `EmailConfirmationAuthProvider.PreAuthenticate` will mark the `CustomUserAuth.EmailConfirmed` as true if the token is valid and not expired. The token is deleted so impossible to authenticate again with that token.
4. I don't know how to add the `EmailConfirmed = true` to the session, nor how to add it on subsequent logins. And I don't know how not to get in the way of other authentication mechanisms.

  1. 实现EmailConfirmationService
代码语言:javascript
复制
1. (Same steps as 1.1 and 1.2)
2. When the user clicks on the link ([https://blabla.com/email-confirmation?token=abcdef](https://blabla.com/email-confirmation?token=abcdef)), the `EmailConfirmationService` will mark the `CustomUserAuth.EmailConfirmed` as true if the token is valid and not expired. Token is deleted and impossible to re-use the same token.
3. I don't know how the session can be re-populated from the `CustomUserAuth`, especially if the user is already authenticated with a JWT token (if `JwtAuthProvider` is part of the `AuthFeature.AuthProviders`). I want to find a way to add a EmailConfirmed flag to the session for all subsequent logins of that user. I didn't find how to "modify" the JWT token (by adding a EmailConfirmed = true), and send it back as a cookie so that it's not necessary to check if the email is confirmed on every request.

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

这条规则的例外情况是,某些服务(标记为属性(比如[AllowUnconfirmedEmail]) )允许用户向他们的地址重新发送确认邮件(比如他们输入了错误的电子邮件地址)。EmailConfirmationService允许通过身份验证的用户向新地址发送新的确认信息。一旦该确认电子邮件被点击,CustomUserAuth.Email & CustomUserAuth.PrimaryEmail将被更新使用新的地址。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-07 03:55:01

请参考ServiceStack认证文档中的高级图表来解释基于会话的Auth提供者Auth提供者是如何工作的.

这些问题中有很多是内部实现细节,当不同的Auth提供者需要它们时,就会调用它们。可以添加要在会议和8月活动中发布的自定义逻辑的用户可重写事件。

PreAuthenticate()Auth提供者调用,它对每个请求进行身份验证,比如API密钥JWT Auth提供程序。通过Authenticate()提供程序进行身份验证时会调用/auth

实施am电子邮件确认

实现用户需要确认的电子邮件的最简单方法可能是实现一个自定义UserSession验证,如下所示:

代码语言:javascript
复制
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表 )的自定义UserAuth表,请参见EmailConfirmed

然后,您的电子邮件服务将是一个服务,它接受一个随机字符串,如Guid (无论是在CustomUserAuth中还是在一个单独的表中),这些字符串引用了哪些用户已经确认了他们的电子邮件。或者,电子邮件中的链接可以再次包含电子邮件,在这种情况下,您可以将其与CustomUserAuth表中的CustomUserAuth字段中的现有电子邮件进行匹配。

如果要在同一个请求中对用户进行身份验证,则可以通过以下方式配置未经过密码验证的请求来允许CredentialsAuthProvider

代码语言:javascript
复制
new CredentialsAuthProvider {
    SkipPasswordVerificationForInProcessRequests = true,
}

它将允许您在同一个“进程中”请求中使用用户名进行身份验证:

代码语言:javascript
复制
using (var service = base.ResolveService<AuthenticateService>()) //In Process
{
    return service.Post(new Authenticate {
        provider = AuthenticateService.CredentialsProvider,
        UserName = request.UserName,
        UseTokenCookie = true, // if using JWT
    });
}

您可以使用只使用HTTP会话验证用户身份的UseTokenCookie,尽管不需要使用JWT。

这个解决方案并不是必需的,但是您可以通过实现CreatePayloadFilter向JWT令牌添加额外的信息,并通过实现PopulateSessionFilter在用户会话中填充额外的元数据。

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

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

基本上,我希望限制用户访问所有被标记为身份验证的服务,这些用户已经确认了他们的电子邮件地址。

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

对于某些服务,这条规则的例外情况是

没有“部分身份验证用户”的概念,您可以进行身份验证(并将经过身份验证的UserSession附加到请求或缓存中),或者没有。我只允许认证,如果他们已经确认了他们的电子邮件,只有更新他们的确认电子邮件,如果他们已经确认了他们的建议电子邮件,他们想要更改为。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56014658

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档