II Deadbolt for Scala
9. Using Deadbolt 2 with Play 2 Scala projects
Deadbolt for Scala provides an idiomatic API for dealing with Scala controllers and templates rendered from Scala controllers in Play applications.
9.1 The Deadbolt Handler
For any module - or framework - to be useable, it must provide a mechanism by which it can be hooked into your application. For Deadbolt, the central hook is the be.objectify.deadbolt.scala.DeadboltHandler trait. The four functions defined by this trait are crucial to Deadbolt - for example, DeadboltHandler#getSubject gets the current user (or subject, to use the correct security terminology), whereas DeadboltHandler#onAccessFailure is used to generate a response when authorization fails.
DeadboltHandler implementations should be stateless.
For each method, a Future is returned. If the future may complete to have an empty value, e.g. calling getSubject when no subject is present, the return type is Future[Option].
Despite the use of the definite article in the section title, you can have as many Deadbolt handlers in your app as you wish.
Performing pre-constraint tests
Before a constraint is applied, the Future[Option[Result]] beforeAuthCheck[A](request: Request[A]) function of the current handler is invoked. If the resulting future completes Some, the target action is not invoked and instead the result of beforeAuthCheck is used for the HTTP response; if the resulting future completes to None the action is invoked with the Deadbolt constraint applied to it.
Obtaining the subject
To get the current subject, the Future[Option[Subject]] getSubject[A](request: Request[A]) function is invoked. Returning a None indicates there is no subject present - this is a valid scenario.
Dealing with authorization failure
When authorization fails, the Future[Result] onAccessFailure[A](request: Request[A]) function is used to obtain a result for the HTTP response. The result required from the Future returned from this method is a regular play.api.mvc.Result, so it can be anything you chose. You might want to return a 403 forbidden, redirect to a location accessible to everyone, etc.
Dealing with dynamic constraints
Dynamic constraints, which are Dynamic and Pattern.CUSTOM constraints, are dealt with by implementations of DynamicResourceHandler; this will be explored in a later chapter. For now, it’s enough to say Future[Optional[DynamicResourceHandler]] getDynamicResourceHandler[A](request: Request[A]) is invoked when a dynamic constraint it used.
9.2 Expose your DeadboltHandlers with a HandlerCache
Deadbolt uses dependency injection to expose handlers in a type-safe manner. Various components of Deadbolt, which will be explored in later chapters, require an instance of be.objectify.deadbolt.scala.cache.HandlerCache - however, no such implementations are provided.
Instead, you need to implement your own version. This trait extends Function[HandlerKey, DeadboltHandler] and Function0[DeadboltHandler] and uses them as follows
-
handlers()will express the default handler - handlers(key: HandlerKey) will express a named handler
Here’s one possible implementation, using hard-coded handlers.
1 @Singleton
2 class MyHandlerCache extends HandlerCache {
3 val defaultHandler: DeadboltHandler = new MyDeadboltHandler
4
5 // HandlerKeys is an user-defined object, containing instances
6 // of a case class that extends HandlerKey
7 val handlers: Map[Any, DeadboltHandler] =
8 Map(HandlerKeys.defaultHandler -> defaultHandler,
9 HandlerKeys.altHandler ->
10 new MyDeadboltHandler(Some(MyAlternativeDynamicResourceHandler)),
11 HandlerKeys.userlessHandler -> new MyUserlessDeadboltHandler)
12
13 // Get the default handler.
14 override def apply(): DeadboltHandler = defaultHandler
15
16 // Get a named handler
17 override def apply(handlerKey: HandlerKey): DeadboltHandler = handlers(handlerKey)
18 }
Finally, create a small module which binds your implementation.
1 package com.example.modules
2
3 import be.objectify.deadbolt.scala.cache.HandlerCache
4 import play.api.inject.{Binding, Module}
5 import play.api.{Configuration, Environment}
6 import com.example.security.MyHandlerCache
7
8 class CustomDeadboltHook extends Module {
9 override def bindings(environment: Environment,
10 configuration: Configuration): Seq[Binding[_]] = Seq(
11 bind[HandlerCache].to[MyHandlerCache]
12 )
13 }
9.3 application.conf
Declare the necessary modules
Both be.objectify.deadbolt.scala.DeadboltModule and your custom bindings module must be declared in the configuration.
1 play {
2 modules {
3 enabled += be.objectify.deadbolt.scala.DeadboltModule
4 enabled += com.example.modules.CustomDeadboltHook
5 }
6 }
9.4 Using compile-time dependency injection
If you prefer to wire everything together with compile-time dependency, you don’t need to create a custom module or add DeadboltModule to play.modules.
Instead, dependencies are handled using a custom ApplicationLoader. To make things easier, various Deadbolt components are made available via the be.objectify.deadbolt.scala.DeadboltComponents trait. You will still need to provide a couple of things, such as your HandlerCache implementation, and you’ll then have access to all the usual pieces of Deadbolt.
1 class CompileTimeDiApplicationLoader extends ApplicationLoader {
2 override def load(context: Context): Application
3 = new ApplicationComponents(context).application
4 }
5
6 class ApplicationComponents(context: Context)
7 extends BuiltInComponentsFromContext(context)
8 with DeadboltComponents
9 with EhCacheComponents {
10
11 // Define a pattern cache implementation
12 // defaultCacheApi is a component from EhCacheComponents
13 override lazy val patternCache: PatternCache = new DefaultPatternCache(defaultCacheApi)
14
15 // Declare something required by MyHandlerCache
16 lazy val subjectDao: SubjectDao = new TestSubjectDao
17
18 // Specify the DeadboltHandler implementation to use
19 override lazy val handlers: HandlerCache = new MyHandlerCache(subjectDao)
20
21 // everything from here down is application-level
22 // configuration, unrelated to Deadbolt, such as controllers, routers, etc
23 // ...
24 }
The components provided by Deadbolt are
-
scalaAnalyzer- constraint logic -
deadboltActions- for composing actions -
actionBuilders- for building actions -
viewSupport- for template constraints -
patternCache- for caching regular expressions. You need to define this yourself in the application loader, but as in the example above it’s easy to use the default implementation -
handlers- the implementation ofHandlerCachethat you provide -
configuration- the application configuration -
ecContextProvider- the execution context for concurrent operations. Defaults toscala.concurrent.ExecutionContext.global -
templateFailureListenerProvider- for listening to Deadbolt-related errors that occur when rendering templates. Defaults to a no-operation implementation
Once you’ve defined your ApplicationLoader, you need to add it to your application.conf.
1 play {
2 application {
3 loader=com.example.myapp.CompileTimeDiApplicationLoader
4 }
5 }
9.5 Tweaking Deadbolt
Deadbolt Scala-specific configuration lives in the deadbolt.scala namespace.
There is one setting, deadbolt.scala.view-timeout, which is millisecond timeout applied to blocking calls when rendering templates. This defaults to 1000ms.
Personally, I prefer the HOCON (Human-Optimized Config Object Notation) syntax supported by Play, so I would recommend the following:
1 deadbolt {
2 scala {
3 view-timeout=500
4 }
5 }
Execution context
By default, all futures are executed in the scala.concurrent.ExecutionContext.global context. If you want to provide a separate execution context, you can plug it into Deadbolt by implementing the DeadboltExecutionContextProvider trait.
1 import be.objectify.deadbolt.scala.DeadboltExecutionContextProvider
2
3 class CustomDeadboltExecutionContextProvider extends DeadboltExecutionContextProvider {
4 override def get(): ExecutionContext = ???
5 }
NB: This provider is invoked twice, once in DeadboltActions and once in ViewSupport. Make sure you take this into account when you implement the get() function.
Once you’ve implemented the provider, you need to declare it in your custom module (see CustomDeadboltHook above for further information).
1 class CustomDeadboltHook extends Module {
2 override def bindings(environment: Environment,
3 configuration: Configuration): Seq[Binding[_]] = Seq(
4 bind[HandlerCache].to[MyHandlerCache],
5 bind[DeadboltExecutionContextProvider].to[CustomDeadboltExecutionContextProvider]
6 )
7 }
10. Scala controller constraints
Controller-level constraints can be added in two different ways - through the use of action builders and through action composition. The resulting behaviour is identical, so choose whichever suites your style best.
10.1 Controller constraints with the action builder
To get started, inject ActionBuilders into your controller.
1 class ExampleController @Inject() (actionBuilder: ActionBuilders) extends Controller
You now have builders for all the constraint types, which we’ll take a quick look at in a minute. In the following examples I’m using the default handler, i.e. .defaultHandler() but it’s also possible to use a different handler with .key(HandlerKey) or pass in a handler directly using .withHandler(DeadboltHandler).
10.2 Controller constraints with action composition
Using the DeadboltActions class, you can compose constrained functions. To get started, inject DeadboltActions into your controller.
1 class ExampleController @Inject() (deadbolt: DeadboltActions) extends Controller
You now have functions equivalent to those of the builders mentioned above. In the following examples I’m using the default handler, i.e. no handler is specified, but it’s also possible to use a different handler with handler = <some handler, possibly from the handler cache>.
10.3 SubjectPresent
Sometimes, you don’t need fine-grained checks - you just need to see if there is a user present.
Action builder
1 def someFunctionA = actionBuilder.SubjectPresentAction().defaultHandler() { Ok(accessOk())\
2 }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
1 def someFunctionA = deadbolt.SubjectPresent() {
2 Action {
3 Ok(accessOk())
4 }
5 }
10.4 SubjectNotPresent
Sometimes, you don’t need fine-grained checks - you just need to see if there is no user present.
Action builder
1 def someFunctionB = actionBuilder.SubjectNotPresentAction().defaultHandler() { Ok(accessOk\
2 ()) }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
1 def someFunctionB = deadbolt.SubjectNotPresent() {
2 Action {
3 Ok(accessOk())
4 }
5 }
10.5 Restrict
Restrict uses a Subject’s Roles to perform AND/OR/NOT checks. The values given to the builder must match the Role.name of the subject’s roles.
AND is defined as an Array[String] (or more correctly, String*), OR is a List[Array[String]], and NOT is a rolename with a ! preceding it.
Action builder
| Parameter | Type | Default | Notes |
|---|---|---|---|
| roles | List[Array[String]] | Allows the definition of OR’d constraints by | |
| having multiple arrays in the list. | |||
| roles | String* | A short-hand of defining a single role or AND | |
| constraint. |
1 def restrictedFunctionA = actionBuilder.RestrictAction("foo")
2 .defaultHandler() { Ok(accessOk()) }
1 def restrictedFunctionB = actionBuilder.RestrictAction("foo", "bar")
2 .defaultHandler() { Ok(accessOk()) }
1 def restrictedFunctionC = actionBuilder.RestrictAction(List(Array("foo"), Array("bar")))
2 .defaultHandler() { Ok(accessOk()) }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| roleGroups | List[Array[String]] | Allows the definition of OR’d constraints by | |
| having multiple arrays in the list. | |||
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
1 def restrictedFunctionA = deadbolt.Restrict(List(Array("foo")) {
2 Action {
3 Ok(accessOk())
4 }
5 }
1 def restrictedFunctionB = deadbolt.Restrict(List(Array("foo", "bar")) {
2 Action {
3 Ok(accessOk())
4 }
5 }
1 def restrictedFunctionB = deadbolt.Restrict(List(Array("foo"), Array("bar")) {
2 Action {
3 Ok(accessOk())
4 }
5 }
10.6 Pattern
Pattern uses a Subject’s Permissions to perform a variety of checks. The check depends on the pattern type.
- EQUALITY - the subject must have a permission whose value is exactly the same as the
valueparameter - REGEX - the subject must have a permission which matches the regular expression given in the
valueparameter - CUSTOM - the
DynamicResourceHandler#checkPermissionfunction is used to determine access
It’s possible to invert the constraint by setting the invert parameter to true. This changes the meaning of the constraint in the following way.
- EQUALITY - the subject must NOT have a permission whose value is exactly the same as the
valueparameter - REGEX - the subject must have NO permissions that match the regular expression given in the
valueparameter - CUSTOM - the
DynamicResourceHandler#checkPermissionfunction, where the OPPOSITE of the Boolean resolved from the function is used to determine access
Action builder
| Parameter | Type | Default | Notes |
|---|---|---|---|
| value | String | The value of the permission. | |
| patternType | PatternType | PatternType.EQUALITY | One of EQUALITY, REGEX or CUSTOM. |
| invert | Boolean | false | Invert the result of the test |
1 def permittedFunctionA = actionBuilders.PatternAction(value = "admin.printer",
2 patternType = PatternType.EQUALITY)
3 .defaultHandler() { Ok(accessOk()) }
1 def permittedFunctionB = actionBuilders.PatternAction(value = "(.)*\.printer",
2 patternType = PatternType.REGEX)
3 .defaultHandler() { Ok(accessOk()) }
1 // the checkPermssion function of the current handler's DynamicResourceHandler
2 // will be used. This is a user-defined test
3 def permittedFunctionC = actionBuilders.PatternAction(value = "something arbitrary",
4 patternType = PatternType.CUSTOM)
5 .defaultHandler() { Ok(accessOk()) }
1 def permittedFunctionB = actionBuilders.PatternAction(value = "(.)*\.printer",
2 patternType = PatternType.REGEX,
3 invert = true)
4 .defaultHandler() { Ok(accessOk()) }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| value | String | The value of the permission. | |
| patternType | PatternType | PatternType.EQUALITY | One of EQUALITY, REGEX or CUSTOM. |
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
| invert | Boolean | false | Invert the result of the test |
1 def permittedFunctionA = deadbolt.Pattern(value = "admin.printer",
2 patternType = PatternType.EQUALITY) {
3 Action {
4 Ok(accessOk())
5 }
6 }
1 def permittedFunctionB = deadbolt.Pattern(value = "(.)*\.printer",
2 patternType = PatternType.REGEX) {
3 Action {
4 Ok(accessOk())
5 }
6 }
1 // the checkPermssion function of the current handler's DynamicResourceHandler
2 // will be used.
3 def permittedFunctionC = deadbolt.Pattern(value = "something arbitrary",
4 patternType = PatternType.CUSTOM) {
5 Action {
6 Ok(accessOk())
7 }
8 }
1 def permittedFunctionB = deadbolt.Pattern(value = "(.)*\.printer",
2 patternType = PatternType.REGEX,
3 invert = true) {
4 Action {
5 Ok(accessOk())
6 }
7 }
10.7 Dynamic
The most flexible constraint - this is a completely user-defined constraint that uses DynamicResourceHandler#isAllowed to determine access.
Action builder
| Parameter | Type | Default | Notes |
|---|---|---|---|
| name | String | The name of the constraint. | |
| meta | String | Additional information for the constraint | |
| implementation to use. |
1 def foo = actionBuilder.DynamicAction(name = "someClassifier")
2 .defaultHandler() { Ok(accessOk()) }
Action composition
| Parameter | Type | Default | Notes |
|---|---|---|---|
| name | String | The name of the constraint. | |
| meta | String | Additional information for the constraint | |
| implementation to use. | |||
| handler | DeadboltHandler | HandlerCache.apply() | The DeadboltHandler instance to use. |
1 def foo = deadbolt.Dynamic(name = "someClassifier") {
2 Action {
3 Ok(accessOk())
4 }
5 }
11. Deadbolt Scala Templates
This is not a client-side DOM manipulation, but rather the exclusion of content when templates are rendered. This also means that any logic inside the constrained content will not execute if authorization fails.
1 @subjectPresent {
2 <!-- paragraphs will not be rendered, satellites will not be repositioned -->
3 <!-- and light speed will not be engaged if no subject is present -->
4 <p>Let's see what this thing can do...</p>
5 @repositionSatellite
6 @engageLightSpeed
7 }
One important thing to note here is that templates are blocking, so any Futures used need to be completed for the resuly to be used in the template constraints. As a result, each constraint can take a function that expresses a Long, which is the millisecond value of the timeout. It defaults to 1000 milliseconds, but you can change this globally by setting the deadbolt.scala.view-timeout value in your application.conf.
11.1 Handlers
By default, template constraints use the default Deadbolt handler but as with controller constraints you can pass in a specific handler. The cleanest way to do this is to pass the handler into the template and then pass it into the constraints. Another advantage of this approach is you can pass in a wrapped version of the handler that will cache the subject; if you have a lot of constraints in a template, this can yield a significant gain.
Fallback content
Each constraint has an xOr variant, which allows you to render content in place of the unauthorized content. This takes the form <constraint>Or, for example subjectPresentOr
1 @subjectPresentOr {
2 <!-- paragraphs will not be rendered, satellites will not be repositioned -->
3 <!-- and light speed will not be engaged if no subject is present -->
4 <p>Let's see what this thing can do...</p>
5 @repositionSatellite
6 @engageLightSpeed
7 } {
8 <marquee>Sorry, you are not authorized to perform clichéd actions from B movies. Suff\
9 er the marquee!</marquee>
10 }
In each case, the fallback content is defined as a second Content block following the primary body.
Timeouts
Because templates use blocking calls when rendering, the futures returned from the Deadbolt handler, etc, need to be completed during the rendering process. A timeout, with a default value of 1000ms, is used to wait for the completion but you may want to change this. You can do this in two ways.
Set a global timeout
If you want to change the default timeout, define deadbolt.scala.view-timeout in your configuration and give it a millisecond value, e.g.
1 deadbolt {
2 scala {
3 view-timeout=1500
4 }
5 }
Use a supplier to provide a timeout
All Deadbolt templates have a timeout parameter which defaults to expressing the app-wide value - 1000L if nothing else if defined, otherwise whatever deadbolt.java.view-timeout is set to. But - and here’s the nice part - the timeout parameter is not a Long but rather a Function0<Long>. This means you can use a timeout that fluctuates based on some metric - say, the number of timeouts that occur during template rendering.
How do I know if timeouts are occurring?
That’s a good question. And the answer is - you need to implement be.objectify.deadbolt.scala.TemplateFailureListener and bind it using a module; see “Expose your DeadboltHandlers with a HandlerCache” section in chapter 8 for more details on this. If you re-use that chapter 8 module, the binding will look something like this.
1 class CustomDeadboltHook extends Module {
2 override def bindings(environment: Environment,
3 configuration: Configuration): Seq[Binding[_]] = Seq(
4 bind[HandlerCache].to[MyHandlerCache],
5 bind[TemplateFailureListener].to[MyTemplateFailureListener]
6 )
7 }
Making it a singleton allows you to keep a running count of the failure level; if you’re using it for other purposes, then scope it accordingly.
11.2 SubjectPresent
Sometimes, you don’t need fine-grained checked - you just need to see if there is a user present.
- be.objectify.deadbolt.scala.views.html.subjectPresent
- be.objectify.deadbolt.scala.views.html.subjectPresentOr
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | handlerCache.apply() | The handler to use to apply the constraint. |
| timeout | () ⇒ Long | A function returning | The timeout applied to blocking calls. |
deadbolt.scala.view-timeout |
|||
| if it’s defined, otherwise | |||
| 1000L |
Example 1
The default Deadbolt handler is used to obtain the subject.
1 @subjectPresent() {
2 This content will be present if handler#getSubject results in a Some
3 }
4
5 @subjectPresentOr() {
6 This content will be present if handler#getSubject results in a Some
7 } {
8 fallback content
9 }
Example 2
A specific Deadbolt handler is used to obtain the subject.
1 @(handler: DeadboltHandler)
2 @subjectPresent(handler = handler) {
3 This content will be present if handler#getSubject results in a Some
4 }
5
6 @subjectPresentOr(handler = handler) {
7 This content will be present if handler#getSubject results in a Some
8 } {
9 fallback content
10 }
11.3 SubjectNotPresent
Sometimes, you don’t need fine-grained checked - you just need to see if there is no user present.
- be.objectify.deadbolt.scala.views.html.subjectNotPresent
- be.objectify.deadbolt.scala.views.html.subjectNotPresentOr
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | handlerCache.apply() | The handler to use to apply the constraint. |
| timeout | () ⇒ Long | A function returning | The timeout applied to blocking calls. |
deadbolt.scala.view-timeout |
|||
| if it’s defined, otherwise | |||
| 1000L |
Example 1
The default Deadbolt handler is used to obtain the subject.
1 @subjectNotPresent() {
2 This content will be present if handler#getSubject results in a None
3 }
4
5 @subjectNotPresentOr() {
6 This content will be present if handler#getSubject results in a None
7 } {
8 fallback content
9 }
Example 2
A specific Deadbolt handler is used to obtain the subject.
1 @(handler: DeadboltHandler)
2 @subjectNotPresent(handler = handler) {
3 This content will be present if handler#getSubject results in a None
4 }
5
6 @subjectNotPresentOr(handler = handler) {
7 This content will be present if handler#getSubject results in a None
8 } {
9 fallback content
10 }
11.4 Restrict
Use Subjects Roles to perform AND/OR/NOT checks. The values given to the constraint must match the Role.name of the subject’s roles.
AND is defined as an Array[String], OR is a List[Array[String]], and NOT is a rolename with a ! preceding it.
- be.objectify.deadbolt.scala.views.html.restrict
- be.objectify.deadbolt.scala.views.html.restrictOr
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | handlerCache.apply() | The handler to use to apply the constraint. |
| roles | List[Array[String]] | The AND/OR/NOT restrictions. One array defines | |
| an AND, multiple arrays define OR. | |||
| timeout | () ⇒ Long | A function returning | The timeout applied to blocking calls. |
deadbolt.scala.view-timeout |
|||
| if it’s defined, otherwise | |||
| 1000L |
Example 1
The subject must have the “foo” role.
1 @restrict(roles = List(Array("foo"))) {
2 Subject requires the foo role for this to be visible
3 }
Example 2
The subject must have the “foo” AND “bar” roles.
1 @restrict(List(Array("foo", "bar")) {
2 Subject requires the foo AND bar roles for this to be visible
3 }
Example 3
The subject must have the “foo” OR “bar” roles.
1 @restrict(List(Array("foo"), Array("bar"))) {
2 Subject requires the foo OR bar role for this to be visible
3 }
Example 3
The subject must have the “foo” OR “bar” roles, or fallback content will be displayed.
1 @restrictOr(List(Array("foo", "bar")) {
2 Subject requires the foo AND bar roles for this to be visible
3 } {
4 Subject does not have the necessary roles
5 }
11.5 Pattern
Use the Subjects Permissions to perform a variety of checks.
- be.objectify.deadbolt.scala.views.html.pattern
- be.objectify.deadbolt.scala.views.html.patternOr
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | handlerCache.apply() | The handler to use to apply the constraint. |
| value | String | The value of the pattern, e.g. a regex or a | |
| precise match. | |||
| patternType | PatternType | PatternType.EQUALITY | |
| timeout | () ⇒ Long | A function returning | The timeout applied to blocking calls. |
deadbolt.scala.view-timeout |
|||
| if it’s defined, otherwise | |||
| 1000L |
Example 1
The subject and DynamicResourceHandler are obtained from the default handler, and must have a permission with the exact value “admin.printer”.
1 @pattern("admin.printer") {
2 Subject must have a permission with the exact value "admin.printer" for this to be vis\
3 ible
4 }
Example 2
The subject and DynamicResourceHandler are obtained from the default handler, and must have a permission that matches the specified regular expression.
1 @pattern("(.)*\.printer", PatternType.REGEX) {
2 Subject must have a permission that matches the regular expression (without quotes) "(.)*\
3 \.printer" for this to be visible
4 }
Example 3
The DynamicResourceHandler is obtained from the default handler and used to apply the custom test
1 @pattern("something arbitrary", PatternType.CUSTOM) {
2 DynamicResourceHandler#checkPermission must result in true for this to be visible
3 }
Example 4
Fallback content is displayed if the user does not have a permission exactly matching “admin.printer”.
1 @patternOr("admin.printer") {
2 Subject must have a permission with the exact value "admin.printer" for this to be vis\
3 ible
4 } {
5 Subject did not have necessary permissions
6 }
11.6 Dynamic
The most flexible constraint - this is a completely user-defined constraint that uses DynamicResourceHandler#isAllowed to determine access.
- be.objectify.deadbolt.scala.views.html.dynamic
- be.objectify.deadbolt.scala.views.html.dynamicOr
| Parameter | Type | Default | Notes |
|---|---|---|---|
| handler | DeadboltHandler | handlerCache.apply() | The handler to use to apply the constraint. |
| name | String | The name of the constraint, passed into the | |
DynamicResourceHandler. |
|||
| meta | PatternType | null | |
| timeout | () ⇒ Long | A function returning | The timeout applied to blocking calls. |
deadbolt.scala.view-timeout |
|||
| if it’s defined, otherwise | |||
| 1000L |
Example 1
The DynamicResourceHandler is obtained from the default handler and is used to apply a named constraint to the content.
1 @dynamic(name = "someName") {
2 DynamicResourceHandler#isAllowed must result in true for this to be visible
3 }
Example 2
The DynamicResourceHandler is obtained from the default handler and is used to apply a named constraint to the content with some hard-coded meta data.
1 @dynamic(name = "someName", meta = "foo") {
2 DynamicResourceHandler#isAllowed must result in true for this to be visible
3 }
Example 3
The DynamicResourceHandler is obtained from the default handler and is used to apply a named constraint to the content with some dynamically-defined meta data.
1 @(someMetaValue: String)
2 @dynamic(name = "someName", meta = someMetaValue) {
3 DynamicResourceHandler#isAllowed must result in true for this to be visible
4 }
Example 4
The DynamicResourceHandler is obtained from a specific handler and is used to apply a named constraint.
1 @(handler: DeadboltHandler)
2 @dynamic(handler = handler, name = "someName") {
3 DynamicResourceHandler#isAllowed must result in true for this to be visible
4 }