2016-02-20 71 views
2

我正在尋找一些方法,使一些認證爲我的發揮框架的應用程序:我想允許/禁止向非認證用戶全部接入HTTP基本身份驗證的遊戲框架2.4

是否存在一些工作模塊/解決方案它?我不需要任何形式的身份驗證,只有401 HTTP響應爲非認證用戶(如Apache .htacccess「AuthType Basic」模式)。

+0

您可能希望看看模塊列表:https://www.playframework.com/modules – cchantep

+0

@cchantep _這些模塊僅適用於Play 1.x系列,現在只讀._ – biesior

回答

1

恐怕沒有這樣的解決方案,原因很簡單:通常當開發人員需要添加授權/認證堆棧時,他們會構建完整的解決方案。最簡單和最快的方式是使用HTTP front-end server作爲您的應用程序的反向代理(我會爲該任務選擇nginx,但是如果您在機器上運行Apache,它也可以使用)。它可以讓你使用通用服務器的規則過濾/驗證流量

此外,它還提供了其他好處,例如:您可以創建類似CDN的路徑,因此您不會浪費應用程序的資源以供公共,靜態資產。您可以使用負載均衡器重新部署應用,而無需完全停止它爲x分鐘,等

+0

以下是Apache的示例配置http://bjeanes.com/2009/09/using-apache-as-a-basicauth-proxy-to-an-internal-re來源 – biesior

2

你也可以用play.mvc.Action解決這個問題,就像這樣。

首先你的行動:

import org.apache.commons.codec.binary.Base64; 
import play.libs.F; 
import play.libs.F.Promise; 
import play.mvc.Action; 
import play.mvc.Http.Context; 
import play.mvc.Result; 
import util.ADUtil; 

public class BasicAuthAction extends Action<Result> { 
    private static final String AUTHORIZATION = "authorization"; 
    private static final String WWW_AUTHENTICATE = "WWW-Authenticate"; 
    private static final String REALM = "Basic realm=\"yourRealm\""; 

    @Override 
    public Promise<Result> call(Context context) throws Throwable { 
     String authHeader = context.request().getHeader(AUTHORIZATION); 
     if (authHeader == null) { 
      context.response().setHeader(WWW_AUTHENTICATE, REALM); 
      return F.Promise.promise(new F.Function0<Result>() { 
       @Override 
       public Result apply() throws Throwable { 
        return unauthorized("Not authorised to perform action"); 
       } 
      }); 
     } 

     String auth = authHeader.substring(6); 
     byte[] decodedAuth = new Base64().decode(auth); 
     String[] credString = new String(decodedAuth, "UTF-8").split(":"); 


     String username = credString[0]; 
     String password = credString[1]; 
     // here I authenticate against AD, replace by your own authentication mechanism 
     boolean loginCorrect = ADUtil.loginCorrect(username, password); 

     if (!loginCorrect) { 
      return F.Promise.promise(new F.Function0<Result>() { 
       @Override 
       public Result apply() throws Throwable { 
        return unauthorized("Not authorised to perform action"); 
       } 
      }); 
     } else { 
      return delegate.call(context); 
     } 
    } 
} 

下一頁您的註釋:

import java.lang.annotation.Documented; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Inherited; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

import play.mvc.With; 


@With(BasicAuthAction.class) 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.METHOD, ElementType.TYPE}) 
@Inherited 
@Documented 
public @interface BasicAuth { 
} 

現在,您可以標註您的控制器功能如下:

@BasicAuth 
public Promise<Result> yourControllerFunction() { 
... 
3

我已經更新Jonck範德Kogel的答案是在解析授權頭時更加嚴格,以便在驗證時不會因爲醜陋的異常而失敗標題是無效的,允許使用密碼 ':',並與播放2.6的工作:

所以,BasicAuthAction類:

import java.io.UnsupportedEncodingException; 
import java.util.concurrent.CompletableFuture; 
import java.util.concurrent.CompletionStage; 

import org.apache.commons.codec.binary.Base64; 

import play.Logger; 
import play.Logger.ALogger; 
import play.mvc.Action; 
import play.mvc.Http; 
import play.mvc.Http.Context; 
import play.mvc.Result; 

public class BasicAuthAction extends Action<Result> { 
    private static ALogger log = Logger.of(BasicAuthAction.class); 

    private static final String AUTHORIZATION = "Authorization"; 
    private static final String WWW_AUTHENTICATE = "WWW-Authenticate"; 
    private static final String REALM = "Basic realm=\"Realm\""; 

    @Override 
    public CompletionStage<Result> call(Context context) { 
     String authHeader = context.request().getHeader(AUTHORIZATION); 
     if (authHeader == null) { 
      context.response().setHeader(WWW_AUTHENTICATE, REALM); 
      return CompletableFuture.completedFuture(status(Http.Status.UNAUTHORIZED, "Needs authorization")); 
     } 

     String[] credentials; 
     try { 
      credentials = parseAuthHeader(authHeader); 
     } catch (Exception e) { 
      log.warn("Cannot parse basic auth info", e); 
      return CompletableFuture.completedFuture(status(Http.Status.FORBIDDEN, "Invalid auth header")); 
     } 

     String username = credentials[0]; 
     String password = credentials[1]; 
     boolean loginCorrect = checkLogin(username, password); 

     if (!loginCorrect) { 
      log.warn("Incorrect basic auth login, username=" + username); 
      return CompletableFuture.completedFuture(status(Http.Status.FORBIDDEN, "Forbidden")); 
     } else { 
      context.request().setUsername(username); 
      log.info("Successful basic auth login, username=" + username); 
      return delegate.call(context); 
     } 
    } 

    private String[] parseAuthHeader(String authHeader) throws UnsupportedEncodingException { 
     if (!authHeader.startsWith("Basic ")) { 
      throw new IllegalArgumentException("Invalid Authorization header"); 
     } 

     String[] credString; 
     String auth = authHeader.substring(6); 
     byte[] decodedAuth = new Base64().decode(auth); 
     credString = new String(decodedAuth, "UTF-8").split(":", 2); 
     if (credString.length != 2) { 
      throw new IllegalArgumentException("Invalid Authorization header"); 
     } 

     return credString; 
    } 

    private boolean checkLogin(String username, String password) { 
     /// change this 
     return username.equals("vlad"); 
    } 
} 

,然後在控制器類:

@With(BasicAuthAction.class) 
public Result authPage() { 
    String username = request().username(); 
    return Result.ok("Successful login as user: " + username + "! Here's your data: ..."); 
}