6

Oto authorisation example from Play Documentation (wersja 2.0.4; starałem się znaleźć nowszą wersję tego dokumentu, ale nie mogłyby):W Play 2.4 z DI, jak korzystać z klasy usług w "zabezpieczonej" funkcji?

trait Secured { 

    def username(request: RequestHeader) = request.session.get(Security.username) 

    def onUnauthorized(request: RequestHeader) = Results.Redirect(routes.Auth.login) 

    def withAuth(f: => String => Request[AnyContent] => Result) = { 
    Security.Authenticated(username, onUnauthorized) { user => 
     Action(request => f(user)(request)) 
    } 
    } 

    def withUser(f: User => Request[AnyContent] => Result) = withAuth { username => implicit request => 
    UserDAO.findOneByUsername(username).map { user => 
     f(user)(request) 
    }.getOrElse(onUnauthorized(request)) 
    } 
} 

Ogólnie jest całkiem prosta, i chciałbym iść z czymś to.

Teraz, zagraj 2.4 zalecanym sposobem jest nie się już używać pojedynczych (jak UserDAO powyżej), ale klasy i wykonawcze DI zamiast (patrz migration guide lub DI docs).

Na przykład, mój serwis i klas repozytorium są określone następująco:

class AuthService @Inject()(accountRepo: AccountRepository) { } 

class AccountRepository { } 

z luzem 2.4 i DI w użyciu, co jest zalecane/„poprawny”/Najprostszym sposobem, aby zdobyć usługi lub DAO (np. AuthService w moim przypadku, lub UserDAO w dokumencie doc) w cechach takich jak Secured?

Czy obecnie ma pan wprowadzić autoryzację dla kontrolerów w zupełnie inny sposób niż używanie takiej cechy?


mogę pracować wzdłuż tych linii:

trait Secured { 
    val authService = GuiceUtils.inject[AuthService]  
    // ... 
} 

Korzystanie pomocnika takiego:

object GuiceUtils { 
    lazy val injector = new GuiceApplicationBuilder().injector()  
    def inject[T: ClassTag]: T = injector.instanceOf[T] 
} 

Jednak zgodnie z odpowiedzią w related question:

W Play możesz użyć wtryskiwacza bezpośrednio tak długo, jak cecha aplikacji jest w zakresie. Ale nie jest to uważane za dobrą praktykę w kodzie produkcyjnym .

Jeśli to prawda, to, co jest za dobrą praktykę w tym przypadku użycia?

Odpowiedz

16

Myślę, że najprostszym podejściem byłoby ogłosić authService w swojej cechy, ale zachować go abstrakcyjne, a następnie mieć kontroler, który rozszerza go obsługi wstrzyknięcia (myślę, że tak działa wtrysk MessagesApi/I18nSupport). Więc możesz zrobić:

trait Secured { 
    val authService: AuthService 
    ... 
} 

controller Application @Inject()(override val authService: AuthService) extends Controller with Secured { 
    ... 
} 
+1

Dzięki, naprawdę bardzo proste! (Musiał dodać 'override val', aby go skompilować.) – Jonik

+0

, ale w ten sposób kontroler ma wiedzę na temat implementacji - authService - która może być używana tylko w funkcji" Secured ". Czy istnieje jakiś sposób, aby wstrzyknąć go tylko do cechy? Podobnie jak w strukturze ciasta? – freakman