我正在尝试在ServiceStack中实施电子邮件确认。我花了5天的时间试图弄清所有身份验证机制,而且我必须说这非常复杂。该代码不容易阅读。
例如,我很难知道:
IAuthProvider.OnAuthenticated
?有时似乎是可选的。IAuthSession.PopulateSession
?与IAuthProvider.PopulateSession
有何不同?IRequest.SaveSession
?IAuthTokens
?为什么它们在某个时候合并?是因为可以通过许多不同的提供程序对用户进行身份验证,并且我们需要合并IAuthTokens
?他们喜欢索赔吗?Session.FromToken
仅用于JWT吗?IAuthWithRequest.PreAuthenticate
和IAuthProvider.Authenticate
有何不同?在这两种方法中应该做什么不同?我收集到每个请求都调用PreAuthenticate,而在使用/ auth / {provider}(在这种情况下为/ auth / email)时调用Authenticate。我想念什么吗?除了这些问题之外,为了解决该问题,我尝试了两种方法:
实现EmailConfirmationAuthProvider
通过添加UserAuth
字段,以CustomUserAuth
覆盖默认bool EmailConfirmed {get;set;}
。
用户注册后,将使用秘密令牌向用户发送电子邮件。该令牌存储在某处。
当用户单击链接(https://blabla.com/auth/email?token=abcdef)时,如果令牌有效且未过期,则EmailConfirmationAuthProvider.PreAuthenticate
会将CustomUserAuth.EmailConfirmed
标记为true。令牌已删除,因此无法再次使用该令牌进行身份验证。
我不知道如何将EmailConfirmed = true
添加到会话中,也不知道如何在后续登录时添加它。而且我不知道如何不妨碍其他身份验证机制。
实施EmailConfirmationService
(与1.1和1.2相同的步骤)
当用户单击链接(https://blabla.com/email-confirmation?token=abcdef)时,如果令牌有效且未过期,则EmailConfirmationService
会将CustomUserAuth.EmailConfirmed
标记为true。令牌已删除,无法重复使用同一令牌。
我不知道如何从CustomUserAuth
重新填充会话,尤其是如果用户已经通过JWT令牌进行了身份验证(如果JwtAuthProvider
是{ {1}})。我想找到一种为该用户的所有后续登录向会话添加EmailConfirmed标志的方法。我没有找到如何“修改” JWT令牌的方法(通过添加EmailConfirmed = true),并将其作为cookie发送回去,这样就不必检查每个请求是否都确认了电子邮件。
基本上,我想将所有标记为AuthFeature.AuthProviders
的服务的访问权限限制为已确认电子邮件地址的用户。如果我错了,请纠正我,但这仅适用于使用凭据注册的用户(如果用户使用[Authenticate]
登录,则电子邮件确认不适用。还是?)
该规则的例外是某些服务(标记为属性GoogleAuthProvider
),这些服务允许用户将确认电子邮件重新发送到其地址(例如,他们输入了错误的电子邮件地址)。 [AllowUnconfirmedEmail]
可以允许经过身份验证的用户将新的确认发送到新地址。单击该确认电子邮件后,EmailConfirmationService
将使用新地址进行更新。
答案 0 :(得分:2)
请参考ServiceStack Authentication Docs中的高级图以说明session based Auth Providers和IAuthWithRequest
Auth Providers的工作方式。
其中许多问题是内部实现细节,它们的不同身份验证提供商在需要它们时会调用它们。您可以添加自定义逻辑的用户可覆盖事件在Session and Auth Events中发布。
Car [0.99]
4 wheel drive [0.03]
color red [0.009]
由IAuthWithRequest
Auth Providers调用,它们对每个请求(例如API Key和JWT 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
将确保只有具有确认电子邮件的用户才能进行身份验证。
此规则的例外是某些服务
您没有通过“部分认证的用户”的概念(或者已将“认证的用户会话”附加到请求或缓存),或者没有。只有在他们确认电子邮件后,我才允许身份验证;如果他们确认要将电子邮件更改为他们的提议电子邮件,则仅更新其确认电子邮件。