2016-12-16 143 views
2

我正在使用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 
    } 
} 
+0

看起來你的解決方案有任何問題。 – aiguy

+0

@aiguy很酷,謝謝!這是第一次實現抽象類..:D – tom12e

+0

使用這種方法將阻止你鏈接其他處理程序。我建議你堅持使用Undertow API(HttpHandler和exchange附件)。如果你有興趣,我可以在實際的答案中詳細說明。 – aramaki

回答

3

更可重複使用和推薦的方法是堅持與暗潮HttpHandler的API和鏈處理一起。

首先,因爲你已經提出了,你的智威湯遜的認證處理,檢查在請求傳入令牌:

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的接口,並預期下一個的HttpHandler來如果成功,請致電。在下一個處理程序調用handleRequest方法之前,請注意將當前有效標記添加爲交換附件的行。附件是一種在處理程序之間傳遞數據的方法。

然後,你HelloHandler簡單地從交換附件需要一個JwtToken(注意,這只是一個猜測,我不知道你用JWT庫做什麼,這簡直就是令牌變量的類型在你的例子中)。

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,你可以輕鬆地集成和使用暗潮提供現有的處理程序,看看here

1

你的做法將迫使子類實現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); 
}