2011-09-14 7 views
21

Voglio applicare il routing https solo per la pagina di accesso della mia applicazione.Applicare il routing Https per l'accesso con il framework di gioco

È possibile farlo con Play! senza l'uso di un server http front-end?

+2

Perché sempre che qualcuno fa una domanda correlate riproduzione quadro ci sono risposte per le versioni 1.xe 2.x? Dato che sono così diversi questo causa solo confusione, se ci fossero solo nomi con nomi diversi ... Come 'Play' e' Run' forse. –

+0

Tutti hanno detto al gioco! team questo quando hanno lanciato 2.0. Non hanno ascoltato. – HelpMeStackOverflowMyOnlyHope

risposta

21

È possibile utilizzare un intercettore @Before per reindirizzare ogni richiesta, anche se l'utente digita http: // direttamente. Di seguito è riportato il codice che utilizzo (funziona quando è in esecuzione senza contenitore play run o quando si esegue dietro un front-end come in Heroku).

public class HttpsRequired extends Controller { 
    /** Called before every request to ensure that HTTPS is used. */ 
    @Before 
    public static void redirectToHttps() { 
     //if it's not secure, but Heroku has already done the SSL processing then it might actually be secure after all 
     if (!request.secure && request.headers.get("x-forwarded-proto") != null) { 
      request.secure = request.headers.get("x-forwarded-proto").values.contains("https"); 
     } 

     //redirect if it's not secure 
     if (!request.secure) { 
      String url = redirectHostHttps() + request.url; 
      System.out.println("Redirecting to secure: " + url); 
      redirect(url); 
     } 
    } 

    /** Renames the host to be https://, handles both Heroku and local testing. */ 
    @Util 
    public static String redirectHostHttps() { 
     if (Play.id.equals("dev")) { 
      String[] pieces = request.host.split(":"); 
      String httpsPort = (String) Play.configuration.get("https.port"); 
      return "https://" + pieces[0] + ":" + httpsPort; 
     } else { 
      if (request.host.endsWith("domain.com")) { 
       return "https://secure.domain.com"; 
      } else { 
       return "https://" + request.host; 
      } 
     } 
    }  
} 
+0

Sei fantastico! –

2

Dovresti essere in grado. Effettuare le seguenti operazioni:

  1. Impostare http.port e https.port nel file application.config
  2. utente @@ {Controller.action() sicuro().} Quando è necessario per puntare a un sicuro pagina. Utilizzare sia @@ per generare un URL completo (compreso https) e sicuro per suggerimento per giocare si vuole il protocollo HTTPS

Questo dovrebbe funzionare

+2

Cosa succede se l'utente digita nella barra degli indirizzi l'URL http: //myapp.org/login invece di https: //myapp.org/login. Quello di cui avrei bisogno sarebbe un reindirizzamento https dal controller login() stesso. – emt14

0

Non sembra essere possibile dal punto di vista del regolatore. Dal modello di soluzione di Pere funziona, ma questo genera solo l'URL https dal modello.

Se l'utente accede all'azione di accesso digitando manualmente o seguendo un collegamento all'URL http, non sembra essere un modo per applicare/reindirizzare a https.

Il modo migliore sembra avere un proxy front-end.

+0

Esistono diversi modi per fare ciò, come puoi vedere in altre risposte –

3

Penso che sia possibile controllare il controller per request.secure == true e quindi reindirizzare a https.

+0

Hai in mente Play 1.x? Non riesco a trovare alcun campo 'request.secure' in Play 2.2. – KajMagnus

+1

'request.sequre' è disponibile in Play 2.3, rilasciato a giugno 2014, consultare i documenti API: http://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api. mvc.RequestHeader – KajMagnus

6

Ecco un esempio che funziona con Java Play 2.1.1 e Heroku.

public class ForceHttps extends Action<Controller> { 

    // heroku header 
    private static final String SSL_HEADER = "x-forwarded-proto"; 

    @Override 
    public Result call(Context ctx) throws Throwable { 
     final Result result; 
     if (Play.isProd() && !isHttpsRequest(ctx.request())) { 
      result = redirect("https://" + ctx.request().host() 
        + ctx.request().uri()); 
     } 
     else { 
      // let request proceed 
      result = this.delegate.call(ctx); 
     } 
     return result; 
    } 

    private static boolean isHttpsRequest(Request request) { 
     // heroku passes header on 
     return request.getHeader(SSL_HEADER) != null 
       && request.getHeader(SSL_HEADER) 
         .contains("https"); 
    } 

} 

Quindi per qualsiasi controller che si desidera verificare la presenza di HTTPS, aggiungere @With (ForceHttps.class). O se vuoi che tutti i controller controllino, quindi aggiungi una classe, HttpsController estende Controller e fa in modo che tutte le tue classi estendano HttpsController.

ad es.

@With(ForceHttps.class) 
public class HttpsController extends Controller { 

} 
+1

Questo ha funzionato senza alcun problema per me in 2.5, con la sola differenza che il tipo di ritorno del metodo di chiamata è ora CompletionStage , quindi è possibile utilizzare CompletableFuture.completedFuture per restituire il reindirizzamento. – jyoung

3

Se la vostra utilizzando AWS, è possibile interrompere l'HTTPS al Load Balancer e utilizzare un filtro per reindirizzare connessione HTTP a HTTPS.

AWS Conf:

443 (Load Balancer) ----------> 80 (Server)

80 (Load Balancer) ---------- > 80 (Server)

Il filtro:

object HTTPSRedirectFilter extends Filter with Logging { 

    def apply(nextFilter: (RequestHeader) => Future[SimpleResult])(requestHeader: RequestHeader): Future[SimpleResult] = { 
     //play uses lower case headers. 
     requestHeader.headers.get("x-forwarded-proto") match { 
      case Some(header) => { 
       if ("https" == header) { 
        nextFilter(requestHeader).map { result => 
         result.withHeaders(("Strict-Transport-Security", "max-age=31536000")) 
        } 
       } else { 
        Future.successful(Results.Redirect("https://" + requestHeader.host + requestHeader.uri, 301)) 
       } 
      } 
      case None => nextFilter(requestHeader) 
     } 
    } 
} 
Problemi correlati