6

下面是一個authorisation example from Play Documentation(2.0.4版本;我試圖找到這個文件的一個新版本,但不能):在Play 2.4中與DI,如何在「安全」特質中使用服務類?

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)) 
    } 
} 

總體而言,這是非常簡單的,我想要去的東西,如這個。

現在,在播放2.4的推薦方法是再使用單因素(像上面的UserDAO),但類和運行時的DI(請參閱第migration guide,或DI docs)。

例如,我的服務和存儲庫類的定義是這樣的:

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

class AccountRepository { } 

隨着播放2.4和DI使用的,什麼是推薦/「正確」 /簡單的得到服務的持有方式或DAO(例如我的案例中的AuthService,或文檔示例中的UserDAO),像Secured這樣的特徵?

或者你現在是否應該以另一種方式實施對控制器的授權而不是使用這種特性?


我可以使它沿着這些路線工作:

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

使用這樣的幫手:

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

但根據在related question答案:

在Play中,您可以直接使用噴油器只要應用 特性在範圍內。但在 生產代碼中這不被認爲是良好的做法。

如果這是真的,那麼在本用例中是否被認爲是良好的做法?

回答

16

我認爲最簡單的方法是在你的trait中聲明authService,但保持它的抽象,然後讓控制器擴展它來處理注入(我相信這是注入工作的方式)。所以你可以這樣做:

trait Secured { 
    val authService: AuthService 
    ... 
} 

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

謝謝,確實很簡單! (必須添加'override val'來編譯它。) – Jonik

+0

但是這種方式控制器具有關於底層實現的知識 - authService - 只能在'Secured'特性中使用。有什麼方法可以只注入特質?就像蛋糕模式一樣? – freakman

相關問題