ServiceStack中的直通身份验证

ton*_*ony 6 c# servicestack

我有两个ServiceStack服务器X和Y.Server X具有注册和验证用户的功能.它具有RegistrationFeature,CredentialsAuthProvider,MemoryCacheClient和MongoDbAuthRepository功能来处理身份验证.最近,我介绍了服务器Y和GUI表单,它们与服务器Y通信以处理我的业务域的另一部分.服务器Y需要向服务器X上的经过身份验证的端点发出请求.

如何配置服务器Y,使其在从GUI表单获取登录请求时,将该职责传递给可以访问用户信息的服务器X?

我尝试在服务器Y中实现自定义CredentialsAuthProvider,如下所示:

public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
    // authenticate through server X
    try
    {
        var client = new JsonServiceClient("http://localhost:8088");
        var createRequest = new Authenticate
        {
            UserName = userName,
            Password = password,
            provider = Name,
        };

        var authResponse = client.Post(createRequest);
        return true;
    }
    catch (WebServiceException ex)
    {
        // "Unauthorized
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

但后来当我尝试从服务器Y中的服务向服务器X中的经过身份验证的端点发出请求时,我收到了Unauthorized错误.

public class MyServices2 : Service
{
    public object Any(TwoPhase request)
    {
        try
        {
            // make a request to server X on an authenticated endpoint
            var client = new JsonServiceClient("http://localhost:8088");

            var helloRequest = new Hello
            {
                Name = "user of server Y"
            };

            var response = client.Post(helloRequest);

            return new TwoPhaseResponse { Result = $"Server X says: {response.Result}" };
        }
        catch (WebServiceException e)
        {
            Console.WriteLine(e);
            throw;
        }
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

myt*_*thz 5

这在很大程度上取决于您选择的身份验证方法.如果要使用CredentialsAuthProvider,则必须确保每个服务器都配置为使用相同的分布式缓存提供程序实例(即除MemoryCacheClient之外的任何缓存提供程序).这是因为当您进行身份验证时,指向经过身份验证的用户会话的会话Cookie ID将填充在随每个请求一起发送的服务客户端上.接收会话Cookie ID的ServiceStack实例将使用它来访问已注册的高速缓存提供程序中的经过身份验证的用户会话.

如果两个ServiceStack服务都配置为使用相同的缓存提供程序,则可以将会话Cookie从传入请求传输到新的服务客户端,例如:

转移会话ID

public object Any(ClientRequest request)
{
    // make a request to server X on an authenticated endpoint
    var session = base.SessionAs<AuthUserSession>();
    var client = new JsonServiceClient("http://localhost:8088");
    client.SetSessionId(session.Id);

    var response = client.Post(new Hello {
        Name = "user of server Y"
    });

    return new TwoPhaseResponse { Result = $"Server X says: {response.Result}" };
}
Run Code Online (Sandbox Code Playgroud)

传输BasicAuthProvider凭据

否则,如果您使用HTTP Basic Auth,BasicAuthProvider那么UserName/Password随请求一起发送,您可以通过以下方式将其传输到内部服务客户端:

var basicAuth = base.Request.GetBasicAuthUserAndPassword();
client.UserName = basicAuth.Value.Key;
client.Password = basicAuth.Value.Value;
client.AlwaysSendBasicAuthHeader = true;
Run Code Online (Sandbox Code Playgroud)

这将复制在传入请求上发送的用户名/密码,并将其与传出请求一起发送.但是,对于这个工作既ServiceStack实例必须配置为使用相同的BasicAuthProvider用户认证信息库,因为下游服务器必须能够验证所提供的用户名/密码.

传输API密钥

同样,您可以使用API Key AuthProvider执行类似的操作,但您可以转发User Key/Password而不是转发User Key:

var apikey = base.Request.GetApiKey();
client.BearerToken = apikey.Id;
Run Code Online (Sandbox Code Playgroud)

同样,这将需要配置相同ApiKeyAuthProvider和用户身份验证存储库,因为下游服务器将需要验证提供的API密钥.

使用JWT AuthProvider进行无状态身份验证

否则,如果您不希望每个服务器共享相同的基础架构依赖关系(例如缓存提供程序/用户身份验证存储库),我会考虑使用JWT身份验证提供程序,这对于使用一个ServiceStack实例进行身份验证的情况非常理想.JWT Token封装了用户会话,并允许您对其他只需要注册JwtAuthProviderReader的 ServiceStack实例进行经过身份验证的请求.

要传输JWT令牌,您可以使用以下命令访问它:

var bearerToken = base.Request.GetBearerToken()
    ?? base.Request.GetCookieValue(Keywords.TokenCookie);
Run Code Online (Sandbox Code Playgroud)

并使用以下内容在内部服务客户端上填充它:

client.BearerToken = bearerToken;
Run Code Online (Sandbox Code Playgroud)