servicestack,Authentication,Asp.net Core,.net Core,Authorization,servicestack" /> servicestack,Authentication,Asp.net Core,.net Core,Authorization,servicestack" />

Authentication ServiceStack-电子邮件确认

Authentication ServiceStack-电子邮件确认,authentication,asp.net-core,.net-core,authorization,servicestack,Authentication,Asp.net Core,.net Core,Authorization,servicestack,我正在尝试在ServiceStack中实现电子邮件确认。我花了5天时间试图弄清楚所有的身份验证机制,我必须说它非常复杂。代码不容易阅读 我很难知道,例如: 为什么调用IAuthProvider.OnAuthenticated?有时它似乎是可选的 为什么调用IAuthSession.PopulateSession?它与IAuthProvider.PopulateSession有何不同 为什么调用IRequest.SaveSession 什么是IAuthTokens?为什么他们会在某个时候合并?这

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

我很难知道,例如:

  • 为什么调用
    IAuthProvider.OnAuthenticated
    ?有时它似乎是可选的
  • 为什么调用
    IAuthSession.PopulateSession
    ?它与IAuthProvider.PopulateSession有何不同
  • 为什么调用
    IRequest.SaveSession
  • 什么是
    IAuthTokens
    ?为什么他们会在某个时候合并?这是因为用户可以通过许多不同的提供者进行身份验证,并且我们需要合并
    IAuthTokens
    ?它们像索赔吗
  • Session.FromToken
    是否仅适用于JWT
  • IAuthWithRequest.PreAuthenticate
    IAuthProvider.Authenticate
    有何不同?在这两种方法中有什么不同的做法?我推测每个请求都会调用预身份验证,使用/auth/{provider}(在本例中为/auth/email)时会调用Authenticate。我错过什么了吗
撇开这些问题不谈,为了解决这个问题,我尝试了两种方法:

  • 实现EmailConfirmationAuthProvider

  • 通过添加
    bool-emailconfirm{get;set;}
    字段,用
    CustomUserAuth
    覆盖默认的
    UserAuth

  • 当用户注册时,会向用户发送一封带有秘密令牌的电子邮件。这个令牌存储在某处

  • 当用户单击链接()时,
    EmailConfirmationAuthenticationProvider.PreAuthentication
    会将
    CustomUserAuth.EmailConfirmation
    标记为true(如果令牌有效且未过期)。令牌被删除,因此无法再次使用该令牌进行身份验证

  • 我不知道如何将
    emailconfirm=true
    添加到会话中,也不知道如何在后续登录时添加它。我不知道怎样才能不妨碍其他身份验证机制

  • 实施
    电子邮件确认服务

  • (步骤与1.1和1.2相同)

  • 当用户单击链接(),如果令牌有效且未过期,
    EmailConfirmationService
    CustomUserAuth.EmailConfirmation
    标记为true。令牌已删除,无法重复使用同一令牌

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

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


    此规则的例外情况是某些服务(用属性标记,例如
    [AllowUnconfirmedMail]
    )允许用户向其地址重新发送确认电子邮件(例如输入了错误的电子邮件地址)。
    EmailConfirmationService
    允许经过身份验证的用户向新地址发送新确认。单击该确认电子邮件后,CustomUserAuth.email和CustomUserAuth.PrimaryEmail将使用新地址更新。

    请参考中的高级图表,以解释其工作原理

    这些问题中有很多是内部实现细节,当不同的身份验证提供者需要它们时,就会调用它们。可以向其中添加自定义逻辑的用户可重写事件将在中发布

    PreAuthenticate()<通过
    /auth
    提供程序进行身份验证时,会调用code>Authenticate()

    实现am电子邮件确认 实现需要确认电子邮件的用户的最简单方法可能是实现类似以下内容的电子邮件:

    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;
        }
    }
    
    这样,您就可以在同一个“进程中”请求中仅使用用户名进行身份验证:

    using (var service = base.ResolveService<AuthenticateService>()) //In Process
    {
        return service.Post(new Authenticate {
            provider = AuthenticateService.CredentialsProvider,
            UserName = request.UserName,
            UseTokenCookie = true, // if using JWT
        });
    }
    
    使用(var service=base.ResolveService),尽管不需要使用JWT

    此解决方案不需要它,但您可以通过实现
    PopulateSessionFilter
    将附加信息添加到JWT令牌,并在用户会话上填充该附加元数据

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

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

    基本上,我想将所有标有[Authenticate]的服务的访问权限限制为已确认其电子邮件地址的用户

    如上所述,在自定义AuthUserSession中重写
    Validate()
    ,将确保只有具有已确认电子邮件的用户才能进行身份验证

    此规则的例外情况是某些服务


    没有“部分身份验证用户”的概念—您要么通过身份验证(并且将身份验证用户会话附加到请求或缓存)或者你不是。我只允许他们确认他们的电子邮件时进行身份验证,只有他们确认了他们要更改的建议电子邮件时才更新他们的确认电子邮件。

    谢谢你的回答。我开始遵循这些准则。CreadentialAuthProvider似乎没有打电话给我
    using (var service = base.ResolveService<AuthenticateService>()) //In Process
    {
        return service.Post(new Authenticate {
            provider = AuthenticateService.CredentialsProvider,
            UserName = request.UserName,
            UseTokenCookie = true, // if using JWT
        });
    }