2016-04-04 32 views
6

Kısaca: Uygulamam Play web framework sürüm 2.5.1'i kullanır. Veritabanımdaki kullanıcı yetki bilgilerine erişmek için the Deadbolt authorization system ve Slick kullanmak istiyorum. Bunu nasıl yapabilirim? Sürgüiçin Çal ve dışı-box, çok kolay değil mümkünse olması gerektiğini, böylece entegre Slick ile gelir oyna özel olarak yapılır.Nasıl Oynatılır (web framework), Deadbolt (yetkilendirme) ve Slick (veritabanı erişimi)

"Integrating Deadbolt" Deadbolt belgelerine dayanarak, DeadboltHandler özelliğini genişlettim. Özet getSubject() yöntemi, veritabanı sorgusu yapmak için yer gibi görünüyor (yani the documentation diyor ama herhangi bir örnek). Bu yöntem bir AuthenticatedRequest argümanı olarak kabul edilir ve temel olarak kullanıcı kimliği doğrulandıktan sonra rol ve izinler (yetkilendirmeler) ile birlikte Subject değerini döndürür.

Takılıyorum çünkü Play, Slick integration ile gelirken, belgeler yalnızca bir Play denetleyicisinden nasıl kullanılacağını açıklar.

başarıyla belirli kaynaklara erişimi kısıtlamak için benim denetleyicisi Sürgü kullanıyorum (küresel aramaları kullanarak artık kullanılmamaktadır ve hataya açık beri Not Bu kullanarak bağımlılık enjeksiyon yapmak isteyen pm), ancak denetleyici gibi görünüyor Deadbolt için yanlış yer, yetkilendirme ayrıntıları için veritabanı sorguları yapıyor (eğer öyleyse, DeadboltHandler amaçsız olurdu). işleri

class Application @Inject()(
    dbConfigProvider: DatabaseConfigProvider, 
    playConfig: play.api.Configuration, 
    deadbolt: DeadboltActions 
) extends Controller { 

: kontrolör yapıcı imza tanım (kontrolör web içeriğini depolayan varsayılan veritabanını ziyade yetki veritabanı erişir not) gibi görünür. Ancak, benzer şekilde @Inject ile DeadboltHandler uzantısı annotating veritabanına Slick erişim sağlamak için başarısız: Sonuç

not enough arguments for constructor AuthHandler: (dbConfigProvider: play.api.db.slick.DatabaseConfigProvider)services.AuthHandler. 
Unspecified value parameter dbConfigProvider. 

Açıkçası

class AuthHandler @Inject()(@play.db.NamedDatabase("auth") dbConfigProvider: DatabaseConfigProvider) 
    extends DeadboltHandler { 

olmak Çal denetleyicileri için özel bir şey yapar ki @Inject ek açıklama çalışması, anlamadığım bir şey. Ben new anahtar sözcüğü yerine bir enjektör kullanarak denetleyicileri oluşturma doğasında olduğunu varsayalım, ama Çal kaynak kodu aracılığıyla arama tam olarak ne olduğunu göstermek için başarısız oldu. Bunu bulabilirsem, belki de bu tekniği bir DeadboltHandler oluşturmak için taklit edebilirim.

Bu oyunun, çözümün bir parçası olabileceğini söyleyen GuiceInjector ve GuiceInjectorBuilder gibi sınıflarla birlikte geldiğini görüyorum, ancak deneylerim nasıl yapıldığını henüz gösteremedi ve nasıl kullanılacağına dair herhangi bir belge varsa Onları, bir DeadboldHandler uzantısının özel bağlamında, özlüyorum.

Bu önceki sorumu zaten buldum: Scala (Play 2.4.x) How to call a class with @inject() annotation, noktasında çok görünüyor. Ne yazık ki, orijinal posterden gelen yarım düzine yorumlara rağmen, henüz cevapsız.(yılında Scala) Çal ve Sürgü ve birbirleriyle Slick nasıl kullanılacağı: Ben bu sorunun cevabını olsaydı benim sorum çok özel olsa ben, bu soruya yanıt olması için hissediyorum.

Beni en çok etkileyen şey, bunun belgelerinde belirtileceği veya önceden SO üzerinde sorulması gerektiği gibi ortak olması gereken bir şey gibi görünüyor. Bu tür referansları bulmadaki başarısızlığım tipik olarak, hiç kimsenin bunun hakkında konuşmak için hiç kimsenin olamayacağı kadar benzersiz bir şekilde yanlış bir şey yaptığım anlamına gelir. Şüphesiz, iyimser bir şekilde, çok temel bir şeyi kaçırdığımı umduğum kadar basit olmalıydı ve bu bilgiden beni haberdar eden bir çeşit ruhu sabırsızlıkla bekliyorum.

+1

Ben tam cevap sonradan yukarı yazacağım ama şimdilik https bir göz atabilirsiniz: // github. com/schaloner/deadbolt-auth0-scala/blob/master/uygulama/güvenlik/MyDeadboltHandler.scala # L37 ve https://github.com/schaloner/deadbolt-auth0-scala/blob/master/app/security/AuthSupport. scala # L56 - bu örnek bir veritabanı yerine harici bir kimlik yönetimi platformu kullanıyor ancak https://github.com/schaloner/deadbolt-auth0-scala/blob/master/app/security/AuthSupport adresini yeniden yazabilmeniz gerekir. .scala # L105 ve d kodun çoğunu olduğu gibi kullanın. –

+0

Beni unutma, Steve'i korusun! Tam bir cevap yazmanız gerektiği sürece alın; Seni bekleyen doğru cevap işaretin var. –

cevap

2

Sorunuzda belirttiğiniz gibi, kullanıcıyı alabileceğiniz yer DeadboltHandler.getSubject. Veritabanına özgü kodu gerçekte kendi sınıfına taşıyabilirsiniz, böylece bu örnekte yaptığım şey budur.

Bu, DeadboltHandler'un genel bir uygulamasıdır; Kalıcılığa daha sonra değinileceğinden, kodu kodunuza bırakabilmeli ve hemen hemen kullanabilmelisiniz.

import javax.inject.{Inject, Singleton} 

import be.objectify.deadbolt.scala.models.Subject 
import be.objectify.deadbolt.scala.{AuthenticatedRequest, DeadboltHandler, DynamicResourceHandler} 
import models.{LogInForm, User} 
import play.api.mvc.{Request, Result, Results} 
import play.twirl.api.HtmlFormat 
import views.html.security.denied 

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.Future 

@Singleton 
class MyDeadboltHandler @Inject() (authSupport: AuthSupport) extends DeadboltHandler { 

    override def beforeAuthCheck[A](request: Request[A]): Future[Option[Result]] = Future {None} 

    override def getDynamicResourceHandler[A](request: Request[A]): Future[Option[DynamicResourceHandler]] = Future {None} 

    /** 
    * Get the current user. 
    * 
    * @param request the HTTP request 
    * @return a future for an option maybe containing the subject 
    */ 
    override def getSubject[A](request: AuthenticatedRequest[A]): Future[Option[Subject]] = 
    Future { 
     request.subject.orElse { 
     // replace request.session.get("userId") with how you identify the user 
     request.session.get("userId") match { 
      case Some(userId) => authSupport.getUser(userId) 
      case _ => None 
     } 
     }} 

    /** 
    * Handle instances of authorization failure. 
    * 
    * @param request the HTTP request 
    * @return either a 401 or 403 response, depending on the situation 
    */ 
    override def onAuthFailure[A](request: AuthenticatedRequest[A]): Future[Result] = { 
    def toContent(maybeSubject: Option[Subject]): (Boolean, HtmlFormat.Appendable) = 
     maybeSubject.map(subject => subject.asInstanceOf[User]) 
     .map(user => (true, denied(Some(user)))) 
     .getOrElse {(false, views.html.security.logIn(LogInForm.logInForm))} 

    getSubject(request).map(maybeSubject => toContent(maybeSubject)) 
    .map(subjectPresentAndContent => 
     if (subjectPresentAndContent._1) Results.Forbidden(subjectPresentAndContent._2) 
     else Results.Unauthorized(subjectPresentAndContent._2)) 
    } 
} 

veritabanına gitmek gerek

şimdi konu zaten istek yerleştirilir edilmemiştir durumlarda düşürülür. Bununla birlikte, kullanıcıyı tanımladığınız halde request.session.get("userId")'un değiştirilmesiyle ilgili yorumu not alın. Konu kalıcılığına erişim AuthSupport sınıfı tarafından sağlanmaktadır. Bu, DB Access'in DeadboltHandler'dan ayrılmasını sağlar. Oldukça basit, çünkü esas olarak bunu Slick sorgunuzla doldurursunuz.

@Singleton 
class AuthSupport @Inject()(dbConfigProvider: DatabaseConfigProvider) { 
    // set up your usual Slick support 

    // use Slick to get the subject from the database 
    def getUser(userId: String): Option[User] = ??? 
} 

bu göstermek için, bir modül oluşturmak ve application.conf içinde kaydettikten gerekir. application.conf bunu bildirme

import be.objectify.deadbolt.scala.DeadboltHandler 
import be.objectify.deadbolt.scala.cache.HandlerCache 
import security.{AuthSupport, MyDeadboltHandler, MyHandlerCache} 
import play.api.inject.{Binding, Module} 
import play.api.{Configuration, Environment} 

class CustomBindings extends Module { 
    override def bindings(environment: Environment, 
         configuration: Configuration): Seq[Binding[_]] = 
    Seq(
     bind[DeadboltHandler].to[MyDeadboltHandler], 
     bind[AuthSupport].toSelf, 
     // other bindings, such as HandlerCache 
     ) 
} 

play.modules.enabled kullanarak olağan meselesidir:

play { 
    modules { 
    enabled += be.objectify.deadbolt.scala.DeadboltModule 
    enabled += modules.CustomBindings 
    } 
} 
+0

Mükemmel, tekrar teşekkürler! Bir soru: 'MyDeadboltHandler' içine' CacheApi' örneğini enjekte ettiniz ama görünüşte kullanılmıyor. Ayrıca, daha fazla önbelleğe alma AuthSupport.getUser() 'de daha uygun yapılmamalıdır? MyDeadboltHandler’a 'cache' enjekte etmenin amacı nedir? –

+1

Örneğime yorum yaptığınız bağlantıdan yorumunuza yeniden yazdım ve önbelleğe alma işlemini basit tutmak için kaldırdım. Önbellek enjeksiyonunu kaldırmayı unuttum - Bunu düzeltmek için düzenledim. –