3

如何在我的验证代码中访问 ServiceStack.net 会话?

public class UserSettingsValidator : AbstractValidator<UserSettingsRequest>
{
    public UserSettingsValidator()
    {
        RuleFor(x => x.UserId)
            .SetValidator(new PositiveIntegerValidator())
            .SetValidator(new UserAccessValidator(session.UserId)); //<-- I need to pass the UserID from the session here
    }
}

在服务实现中,我只是这样做:

var session = base.SessionAs<UserSession>();

但这不适用于我的抽象验证器。

谢谢!

编辑:这是版本 3.9.71.0

4

2 回答 2

7

我假设你只是在使用ValidationFeature插件,就像大多数人一样。如果是这样的话,那我认为这是不可能的。最终,它ValidationFeature是一个使用RequestFilter.

我以前也想做类似的事情,然后意识到这是不可能的。

RequestFilter之前运行ServiceRunner。请参阅此处的操作顺序指南

这对您意味着您填充的请求 DTO 到达您的服务,并且验证功能的请求过滤器将尝试验证您的请求,甚至在它创建ServiceRunner.

ServiceRunner是您的服务类的实例变为活动状态的地方。将与您的对象一起注入的是您的服务类实例UserSession

因此,此时您无法进行任何依赖于会话的验证。

过于复杂?:

可以在您的服务方法中进行验证,您可以创建一个自定义对象,允许您将会话与要验证的对象一起传递。(见下一节)。但我会问自己,你是否过于复杂了你的验证?

UserId对于与会话匹配的请求的简单检查UserId,大概您正在这样做,因此用户只能更改他们自己的记录;为什么不检查服务的操作方法并抛出一个Exception?我猜人们不应该改变这个 ID,所以这不是一个验证问题,而是一个安全异常。但就像我说的,也许你的情况不同。

public class SomeService : Service
{
    public object Post(UserSettingsRequest request) // Match to your own request
    {
        if(request.UserId != Session.UserId)
            throw new Exception("Invalid UserId");
    }
}

服务操作中的验证:

您应该阅读有关使用 Fluent Validators的内容。您可以在服务方法中自己调用自定义验证器。

// This class allows you to add pass in your session and your object
public class WithSession<T>
{
    public UserSession Session { get; set; }
    public T Object { get; set; }
}

public interface IUserAccessValidator
{
    bool ValidUser(UserSession session);
}

public class UserAccessValidator : IUserAccessValidator
{
    public bool ValidUser(UserSession session)
    {
        // Your validation logic here
        // session.UserId
        return true;
    }
}

public class UserSettingsValidator : AbstractValidator<WithSession<UserSettingsRequest>>
{
    public IUserAccessValidator UserAccessValidator { get; set; }

    public UserSettingsValidator()
    {
        // Notice check now uses .Object to access the object within
        RuleFor(x => x.Object.UserId)
            .SetValidator(new PositiveIntegerValidator());

        // Custom User Access Validator check, passing the session
        RuleFor(x => x.Session).Must(x => UserAccessValidator.ValidUser(x)); 
    }
}

然后在您的服务中实际使用验证器:

public class SomeService : Service
{
    // Validator with be injected, you need to registered it in the IoC container.
    public IValidator<WithSession<UserSettingsRequest>> { get; set; }

    public object Post(UserSettingsRequest request) // Match to your own request
    {
        // Combine the request with the current session instance
        var requestWithSession = new WithSession<UserSettingsRequest> {
            Session = this.Session,
            Object = request
        };

        // Validate the request
        ValidationResult result = this.Validator.Validate(requestWithSession);
        if(!result.IsValid)
        {
            throw result.ToException();
        }

        // Request is valid
        // ... more logic here
        return result;
    }
}

我希望这有帮助。注意:代码未经测试

于 2013-12-15T16:39:16.903 回答
2

看来,在阅读了一群遇到类似问题的人之后,然后花了几个小时玩了几个基于 SS4 Cookbook 等的解决方案,这是一个已经解决的问题:

https://forums.servicestack.net/t/blaz-miheljak-355-feb-3-2015/176/2

在你的验证器上实现 IRequiresRequest 接口,瞧。

于 2015-12-06T00:36:18.450 回答