2015-06-09 6 views
1

В следующем Controller, Authenticated извлекает токен из заголовков запроса и вызывает данное действие тогда и только тогда, когда токен действителен (для ясности код был упрощен):Play Framework: как добавить заголовок для каждого ответа

object MyController extends Controller { 

    def Authenticated(action: Token => EssentialAction) = EssentialAction { requestHeader => 
    val jwt = requestHeader.headers.get(HeaderNames.AUTHORIZATION) match { 
     case Some(header) => s"""$AuthScheme (.*)""".r.unapplySeq(header).map(_.head.trim) 
     case _ => requestHeader.getQueryString("auth").map(UriEncoding.decodePath(_, SC.US_ASCII.name)) 
    } 

    jwt match { 
     case Some(t) if t.isValid => 
     val token: Token = authService.token(t) 
     action(token)(requestHeader) 
     case _ => Done(Unauthorized.withHeaders(HeaderNames.WWW_AUTHENTICATE -> AuthScheme)) 
    } 
    } 

    def getUser(userId: String) = Authenticated { token => 
    Action.async { request => 
     userService.find(userId).map { 
     case Some(user) => Ok(Json.obj("user" -> user.asJson)).withHeaders(
      "token" -> authService.renew(token).asJson.toString 
     ) 
     case _ => NotFound 
     } 
    } 
    } 
} 

токен, возвращаемый authService.token(t) является JWT (JSON веб-токен), и он может быть использован только один раз ... так что мне нужно, чтобы вернуть новый маркер после каждого запроса. Идея заключалась бы в том, чтобы поместить новый токен в заголовки ответов. Тем не менее, есть ли способ добавить заголовок token для каждого ответа без необходимости вызывать withHeader в каждом действии?

ответ

6

Просто вы можете создать Фильтр и в Global.scala добавить класс WithFilters.

import play.api.mvc._ 

object Global extends WithFilters(TokenFilter) { 
    ... 
} 

Вот образец фильтра для регистрации, чтобы вы могли легко его изменить, чтобы удовлетворить ваши потребности.

val loggingFilter = Filter { (next, rh) => 
    val start = System.currentTimeMillis 

    def logTime(result: PlainResult): Result = { 
    val time = System.currentTimeMillis - start 
    Logger.info(s"${rh.method} ${rh.uri} took ${time}ms and returned ${result.header.status}") 
    result.withHeaders("Request-Time" -> time.toString) 
    } 

    next(rh) match { 
    case plain: PlainResult => logTime(plain) 
    case async: AsyncResult => async.transform(logTime) 
    } 
} 
1

Я бы использовал ActionComposition. В Java это может выглядеть так:

public class YourActionComposition extends Action<YourAnnotation> { 

    @With(YourActionComposition.class) 
    @Target({ ElementType.TYPE, ElementType.METHOD }) 
    @Retention(RetentionPolicy.RUNTIME) 
    public @interface YourAnnotation { 
    } 

    public F.Promise<Result> call(Http.Context ctx) throws Throwable { 
    Promise<Result> call = delegate.call(ctx); 
    // Add something to your headers here 
    return call; 
    } 
} 
Смежные вопросы