【问题标题】:Calling a abstract method from a callback inside a abstract class从抽象类中的回调调用抽象方法
【发布时间】:2017-05-02 16:53:36
【问题描述】:

我使用 undertow 作为我的 HTTP 库,并希望验证每个请求的 JWT 令牌和 HTTP 方法。我不想在每个HttpHandler 中实现验证。这是正确的做法吗?

Handler.java

public abstract class Handler implements HttpHandler {

    private HttpString[] methods;

    Handler(HttpString... methods) {
        this.methods = methods;
    }

    @Override
    public void handleRequest(HttpServerExchange httpServerExchange) throws Exception {
        // verifying HTTP method
        boolean verified = false;
        for (HttpString method : methods) {
            if (httpServerExchange.getRequestMethod().equals(method)) {
                verified = true;
                break;
            }
        }

        if (!verified) {
            // return http 405, cause: invalid HTTP method
            httpServerExchange.setStatusCode(StatusCodes.METHOD_NOT_ALLOWED);
            httpServerExchange.getResponseSender().send(Variables.Response.EMPTY);
        }

    // verifying JWT token
    String jwt = httpServerExchange.getRequestHeaders().get("jwt", 0);
    JWT.verifyToken(jwt)
            .addListener(token -> {
                if (token != null) {
                    handleVerifiedRequest(httpServerExchange, token);
                } else {
                    // return http 400, cause: JWT invalid
                    httpServerExchange.setStatusCode(StatusCodes.UNAUTHORIZED);
                    httpServerExchange.getResponseSender().send(Variables.Errors.INVALID_JWT);
                }
            });
    }

    public abstract void handleVerifiedRequest(HttpServerExchange httpServerExchange, String Token);
}

HelloHandler.java

public class HelloHandler extends Handler {

    public HelloHandler(HttpString... methods) {
        super(methods);
    }

    @Override
    public void handleVerifiedRequest(HttpServerExchange httpServerExchange, String Token) {
        // .. do something
    }
}

【问题讨论】:

  • 看起来您的解决方案没有任何问题。
  • @aiguy 酷,谢谢!这是第一次实现一个抽象类.. :D
  • 使用这种方法会阻止你链接其他处理程序。我建议您坚持使用 Undertow API(HttpHandler 和交换附件。)如果您有兴趣,我可以详细说明实际答案。
  • @aramaki 我很感兴趣,我将不胜感激。

标签: java undertow


【解决方案1】:

更可重用和推荐的方法是坚持使用 Undertow HttpHandler API 并将处理程序链接在一起。

首先,正如您已经提出的,您的 JWT 身份验证处理程序检查请求中的传入令牌:

public class JwtAuthHandler implements HttpHandler {

  AttachmentKey<JwtToken> JWT_TOKEN = AttachmentKey.create(JwtToken.class);

  private final HttpHandler next;
  public JwtAuthHandler(HttpHandler next) {
    this.next = next;
  }

  @Override
  public void handleRequest(HttpServerExchange exchange) throws Exception {
    ...
    JWT.verifyToken(jwt)
        .addListener(token -> {
          if (token != null) {
            exchange.putAttachment(JWT_TOKEN, token);
            next.handleRequest(exchange);
          } else {
            // return http 400, cause: JWT invalid
            httpServerExchange.setStatusCode(StatusCodes.UNAUTHORIZED);
            httpServerExchange.getResponseSender().send(Variables.Errors.INVALID_JWT);
          }
        });
  }
}

虽然有一个区别,它只是实现了 HttpHandler 接口并期望 next HttpHandler 在成功的情况下调用。在下一个处理程序上调用 handleRequest 方法之前,请注意将当前有效令牌添加为交换附件的行。附件是在处理程序之间传递数据的一种方式。

然后,您的 HelloHandler 只是期望从交换附件中获得一个 JwtToken(注意,这只是一个猜测,我不知道您使用什么 JWT 库,这只是token 变量在您的示例中。)

public class HelloHandler implements HttpHandler {

  @Override
  public void handleRequest(HttpServerExchange exchange) throws Exception {
    JwtToken token = exchange.getAttachment(JWT_TOKEN);
    ...
  }
}

只有在请求认证成功时才会调用这个处理程序。

您可能知道,处理程序应该被链接在一起:

Undertow.builder()
    .addHttpListener(8080, "0.0.0.0")
    .setHandler(new JwtAuthHandler(new HelloHandler()))
    .build().start();

如果您坚持使用 HttpHandler API,则可以轻松集成和使用 Undertow 提供的现有处理程序,请查看 here

【讨论】:

    【解决方案2】:

    您的方法将强制子类实现handleVerifiedRequest,但也会允许某人重新实现handleRequest 以规避您的验证。要防止子类这样做,请将 final 关键字添加到抽象类的原始方法中。

    public abstract class Handler implements HttpHandler {
        // ... //
    
        @Override
        public final void handleRequest(HttpServerExchange httpServerExchange) throws Exception {
           // ... your verification code ... //
        }
    
        public abstract void handleVerifiedRequest(HttpServerExchange httpServerExchange, String Token);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-21
      • 1970-01-01
      • 2016-06-20
      • 1970-01-01
      • 2021-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多