8

セキュリティで保護されていない方法でアクセスされている場合、いくつかのメソッドを制限したいと考えています。リクエストが安全なチャネルを介して送信されたかどうかを確認する @Secure アノテーションを作成しています。ただし、リクエストの HttpContext をキャプチャするメソッド injectable を作成することはできません。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Secure {

}

public class SecureProvider<T> implements InjectableProvider<Secure, AbstractResourceMethod> {
    @Override
    public ComponentScope getScope() {
        return ComponentScope.PerRequest;
    }

    @Override
    public Injectable<?> getInjectable(ComponentContext componentContext,
                                       Secure annotation,
                                       AbstractResourceMethod method) {
        return new SecureInjectable();
    }
}

public class SecureInjectable<T> extends AbstractHttpContextInjectable<T> {
    @Override
    public T getValue(HttpContext context) {    
        // validation here

        return null;
    }
}

私は Dropwizard フレームワークを使用しているため、プロバイダーの初期化は次のように簡単です。

environment.addProvider(new SessionRestrictedToProvider<>(new SessionAuthenticator(), "MySession"));
environment.addProvider(new SecureProvider<>());
environment.setSessionHandler(new SessionHandler());

使用法:

@Resource
@Path("/account")
public class AccountResource {
    @GET
    @Path("/test_secure")
    @Secure
    public Response isSecure() {
        return Response.ok().build();
    }
}

この時点で、メソッドで HttpContext Injectable が機能しないと想定していますが、このアノテーションを実装するために利用できる他のオプションについて途方に暮れています。

4

3 に答える 3

9

編集これはJAX-RS 2.0で動作します。Jersey は現在バージョン 2.4.1 ですが、Dropwizard は残念ながらまだ 1.17.1 を使用しています :(.

ContainerRequestFilter注釈と一緒に使用できます。

まず、注釈:

// need a name binding annotation
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Secure { }

次に、フィルター:

// filter will only be run for methods that have @Secure annotation
@Secure
public class SecureFilter implements ContainerRequestFilter
{
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException
    {
        // check if HTTPS
        if (!requestContext.getSecurityContext().isSecure())
        {
            // if not, abort the request
            requestContext.abortWith(Response.status(Response.Status.BAD_REQUEST)
                                             .entity("HTTPS is required.")
                                             .build());
        }
    }
}

最後に、フィルターを登録します。これは、Jersey アプリの設定方法によって異なります。設定方法は 2 つありますが、他にも多くの可能性があるため、すべてを説明することはしません。

ResourceConfigグリズリーを持っている場合は、これが必要です:

final ResourceConfig rc = new ResourceConfig()
            .packages("my.package.for.resources")
            .register(SecureFilter.class);

カスタム アプリケーション モデルを使用している場合:

public class MyApplication extends ResourceConfig {
    public MyApplication() {
        packages("my.package.for.resources");
        register(SecureFilter.class);
    }
}

使用法:

@Resource
@Path("/account")
public class AccountResource {

    // filter will run for this method
    @GET
    @Path("/test_secure")
    @Secure
    public Response isSecure() {
        return Response.ok().build();
    }

    // filter will NOT run for this method
    @GET
    @Path("/test_insecure")
    public Response allowInsecure() {
        return Response.ok().build();
    }
}
于 2013-12-16T13:14:14.553 に答える
6

AOP を使いたくない場合は、ResourceMethodDispatchProvider と ResourceMethodDispatchAdapter を実装することで実現できると思います。

public class CustomDispatchProvider implements ResourceMethodDispatchProvider {

ResourceMethodDispatchProvider provider;

CustomDispatchProvider(ResourceMethodDispatchProvider provider)
{
    this.provider = provider;
}

@Override
public RequestDispatcher create(AbstractResourceMethod abstractResourceMethod) {
    System.out.println("creating new dispatcher for " + abstractResourceMethod);

    RequestDispatcher defaultDispatcher = provider.create(abstractResourceMethod);
    if (abstractResourceMethod.getMethod().isAnnotationPresent(Secure.class))
        return new DispatcherDecorator(defaultDispatcher);
    else
        return defaultDispatcher;
}

@Provider
public static class CustomDispatchAdapter implements ResourceMethodDispatchAdapter
{

    @Override
    public ResourceMethodDispatchProvider adapt(ResourceMethodDispatchProvider provider) {
        return new CustomDispatchProvider(provider);
    }

}

public static class DispatcherDecorator implements RequestDispatcher
{
    private RequestDispatcher dispatcher;

    DispatcherDecorator(RequestDispatcher dispatcher)
    {
        this.dispatcher = dispatcher;
    }

    public void dispatch(Object resource, HttpContext context) {
        if (context.getRequest().isSecure())
        {
            System.out.println("secure request detected");
            this.dispatcher.dispatch(resource, context);
        }
        else
        {
            System.out.println("request is NOT secure");
            throw new RuntimeException("cannot access this resource over an insecure connection");
        }

    }

}
}

Dropwizard で、次のようにプロバイダーを追加します: environment.addProvider(CustomDispatchAdapter.class);

于 2013-12-16T19:13:56.530 に答える