扩展服务堆栈身份验证 - 使用自定义用户身份验证元数据填充用户会话

off*_*ert 8 servicestack

我正在尝试扩展Service Stack的身份验证和注册功能.我的身份验证和注册工作正常,但我需要为每个用户添加一些自定义数据.从Service Stack的文档和我发现的其他各种帖子中,您可以使用UserAuth表中内置的MetaData列添加自己的数据.

我创建了一个CustomAuthRepository,所以我可以设置UserAuth的元数据属性,这是我的自定义仓库:

public class CustomAuthRepository : OrmLiteAuthRepository, IUserAuthRepository
{
    public UserAuth CreateUserAuth(UserAuth newUser, string password)
    {
        newUser.Set(new LoginInfo
        {
            IsActive = false,
            PasswordNeedsReset = true
        });
        return base.CreateUserAuth(newUser, password);
    }
}
Run Code Online (Sandbox Code Playgroud)

这对于设置元数据非常有用,我最终在UserAuth表的元数据列中使用了LoginInfo对象的序列化版本.

现在我要做的是当用户进行身份验证时,我需要根据某些元数据更改AuthResponse.例如,如果用户尚未激活,我想返回带有属性的AuthResponseIsActive = get value from custom meta data

如果我可以将自定义元数据导入AuthSession,我想我可以这样做.在我的自定义凭证auth提供程序中,我可以根据AuthSession中的内容更改响应对象:

public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
    public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request)
    {
        var customUserAuthSession = (CustomUserAuthSession)session;

        if (!customUserAuthSession.LoginInfo.IsActive)
        {
            return new
            {
                UserName = customUserAuthSession.UserName,
                IsActive = customUserAuthSession.LoginInfo.IsActive
            };
        }

        var isAuthenticated = base.Authenticate(authService, session, request);

        return isAuthenticated;
    } 
}
Run Code Online (Sandbox Code Playgroud)

我是以正确的方式进行此操作,还是有更好的方法来存储和检索自定义元数据?

如何根据用户的自定义元数据更改AuthResponse?

如何将自定义元数据导入AuthSession?

编辑 我越来越接近我想要做的事情.在我的CustomAuthSession OnAuthenticated()方法中:

    public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo)
    {
        var customUserAuthSession = (CustomUserAuthSession) session;

        var userAuth = authService.ResolveService<IUserAuthRepository>().GetUserAuth(session, null);
        customUserAuthSession.LoginInfo = userAuth.Get<LoginInfo>();

        authService.SaveSession(customUserAuthSession);

        base.OnAuthenticated(authService, session, tokens, authInfo);
    }
Run Code Online (Sandbox Code Playgroud)

我正在重新获取UserAuth并使用我需要的数据填充会话.根据自定义用户会话的服务堆栈文档,您需要在使用某些自定义数据填充会话后保存会话.我这样做但它似乎没有保存.在我的CustomCredentialsAuthProvider,Authenticate方法中,我没有看到我添加到会话中的自定义数据.

编辑 我上面第一次编辑的问题是用户获得了身份验证,然后我们转到CustomAuthSession代码,我可以检查它们是否处于活动状态.在它们不活动的情况下,我需要将它们记录下来,这并不理想.

我找到了我可以在我的自定义CredentialsAuthProvider的Authenticate方法中完成所有这些操作.

    public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request)
    {
        var userAuthRepo = authService.ResolveService<IUserAuthRepository>();
        var userAuth = userAuthRepo.GetUserAuthByUserName(request.UserName);
        var loginInfo = userAuth.Get<LoginInfo>();

        if (!loginInfo.IsActive)
        {
            return new CustomAuthResponse
            {
                UserName = userAuth.UserName,
                ResponseStatus = new ResponseStatus("500"),
                IsActive = loginInfo.IsActive
            };
        }

        var authResponse = (AuthResponse)base.Authenticate(authService, session, request);

        return authResponse;
    }
Run Code Online (Sandbox Code Playgroud)

当请求进入时,我可以使用请求中的用户名来获取UserAuth,并检查用户是否是IsActive.如果没有,那么我可以在Service Stack验证它们之前返回一些错误.

我认为这对我想做的事情来说效果很好.我应该能够向客户端返回一个错误,说用户没有激活.

如果有人有一个更干净的方式来做这个将是伟大的.

off*_*ert 8

到目前为止,这是我的答案.它可以工作,我可以做我想做的事情,但我很想听到一些Service Stack的人知道这是否是最好的方法.

保存自定义元数据

创建一个子类化的新类OrmLiteAuthRepository.在我的情况下,我只想使用Service Stack内置的Sql数据库持久性,并让它创建所需的表.

重新实现CreateUserAuth方法以保存任何自定义元数据:

    public UserAuth CreateUserAuth(UserAuth newUser, string password)
    {
        newUser.Set(new AccountStatus
        {
            IsActive = false,
            PasswordNeedsReset = true
        });
        return base.CreateUserAuth(newUser, password);
    }
Run Code Online (Sandbox Code Playgroud)

获取自定义元数据

创建一个子类CredentialsAuthProvider的新类.覆盖Authenticate方法.

    public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request)
    {
        var userAuthRepo = authService.ResolveService<IUserAuthRepository>();
        var userAuth = userAuthRepo.GetUserAuthByUserName(request.UserName);
        var accountStatus= userAuth.Get<AccountStatus>();

        if (!accountStatus.IsActive)
        {
            throw new InvalidOperationException(string.Format("User {0} is not activated.", request.UserName));
        }
        if (!accountStatus.PasswordNeedsReset)
        {
            throw new InvalidOperationException("Your password needs to be reset before you can login.");
        }

        var authResponse = (AuthResponse)base.Authenticate(authService, session, request);

        return authResponse;
    }
Run Code Online (Sandbox Code Playgroud)

当身份验证请求进入此方法时,请获取UserAuth和自定义元数据.如果用户处于非活动状态,或者需要重置其密码,则会抛出带有错误消息的InvalidOperationException.

在我的客户端应用程序的登录控制器中,我可以检查从服务返回的错误消息,并将用户重定向到某个页面,说明帐户尚未激活,或者需要重置其密码才能进行身份验证.