Template constraints

Using template constraints, you can exclude portions of templates from being generated on the server-side. This is not a client-side DOM manipulation! Template constraints have the same possibilities as controller constraints.

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.

One important thing to note here is that templates are blocking, so any Futures used need to be completed for the result 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.

Each constraint has a variant which allows you to define fallback content. This comes in the format <constraintName>Or, e.g.

@subjectPresentOr {
  this is protected
} {
  this will be shown if the constraint blocks the other content
}

Template constraints without controller constraints

It's perfectly reasonable to use template constraints in templates coming from unconstrained controller actions. However, without using a controller constraint there will not be an AuthenticatedRequest available.

To fix this, you can manually create an instance of AuthenticatedRequest but this may result in your code becoming unnecessarily messy.

A better alternative is to use WithAuthRequest - this is essentially a constraint that doesn't actually constrain anything. It simply calls getSubject from the Deadbolt handler and combines it with the current request to create an authenticated request.

class ExampleController @Inject() (deadbolt: DeadboltActions) extends Controller {
  def index = deadbolt.WithAuthRequest()() { authRequeset =>
    Ok(myTemplate())
  }
}

If you prefer to inject ActionBuilders, the same mechanism is available as WithAuthRequestAction.

SubjectPresent

@import be.objectify.deadbolt.scala.views.html.{subjectPresent, subjectPresentOr}

@subjectPresent() {
  This content will be present if handler#getSubject results in a Some 
}

@subjectPresentOr() {
  This content will be present if handler#getSubject results in a Some 
} {
  fallback content
}

SubjectNotPresent

@import be.objectify.deadbolt.scala.views.html.{subjectNotPresent, subjectNotPresentOr}

@subjectNotPresent() {
  This content will be present if handler#getSubject results in a None 
}

@subjectNotPresentOr() {
  This content will be present if handler#getSubject results in a None 
} {
  fallback content
}

Restrict

As with the Restrict controller constraint, an Array means AND and a List[Array] means OR .

@import be.objectify.deadbolt.scala.views.html.{restrict, restrictOr}

@restrict(roles = List(Array("foo", "bar"))) {
  Subject requires the foo role for this to be visible
}

@restrict(List(Array("foo", "bar"))) {
  Subject requires the foo AND bar roles for this to be visible
}

@restrict(List(Array("foo"), Array("bar"))) {
  Subject requires the foo OR bar role for this to be visible
}

@restrictOr(List(Array("foo", "bar"))) {
  Subject requires the foo AND bar roles for this to be visible
} {
  Subject does not have the necessary roles
}

That whole and/or/array/list thing looks pretty ugly, so instead you can use anyOf, allOf and allOfGroup from the be.objectify.deadbolt.scala package object instead.

  • allOf can be used to define an AND relationship, e.g. Array("foo", "bar") can be written as allOf("foo", "bar") - this would then need to be placed in a list for use within a restriction.
  • anyOf can be used to define an OR relationship, e.g. List(Array("foo"), Array("bar")) can be written as anyOf(allOf("foo"), allOf("bar")).
  • allOfGroup is a convenient way of defining a single AND relationship, e.g. List(Array("foo", "bar")) can be written as allOfGroup("foo", "bar").

This means the previous template can be rewritten as this.

@import be.objectify.deadbolt.scala.views.html.{restrict, restrictOr}
@import be.objectify.deadbolt.scala.{allOf, allOfGroup, anyOf}

@restrict(roles = allOfGroup("foo", "bar")) {
  Subject requires the foo role for this to be visible
}

@restrict(allOfGroup("foo", "bar")) {
  Subject requires the foo AND bar roles for this to be visible
}

@restrict(anyOf(allOf("foo"), allOf("bar"))) {
  Subject requires the foo OR bar role for this to be visible
}

@restrictOr(allOfGroup("foo", "bar")) {
  Subject requires the foo AND bar roles for this to be visible
} {
  Subject does not have the necessary roles
}

Pattern

The default pattern type is PatternType.EQUALITY.

@import be.objectify.deadbolt.scala.views.html.{pattern, patternOr}

@pattern("admin.printer") {
  Subject must have a permission with the exact value "admin.printer" for this to be visible
}

@pattern("(.)*\.printer", PatternType.REGEX) {
  Subject must have a permission that matches the regular expression (without quotes) "(.)*\.printer" for this to be visible
}

@pattern("something arbitrary", PatternType.CUSTOM) {
  DynamicResourceHandler#checkPermission must result in true for this to be visible
}

@patternOr("admin.printer") {
  Subject must have a permission with the exact value "admin.printer" for this to be visible
} {
  Subject did not have necessary permissions
}

As with the Pattern controller constraint, it is also possible to provide extra information to custom constraints with the meta: Option[Any] parameter. Meta information specified to an equality or regex pattern constraint will be ignored.

Dynamic

@import be.objectify.deadbolt.scala.views.html.{dynamic, dynamicOr}

@dynamic("someName") {
  DynamicResourceHandler#isAllowed must result in true for this to be visible
}

@dynamicOr("someName") {
  DynamicResourceHandler#isAllowed must result in true for this to be visible
} {
  Custom test failed
}

As with the Dynamic controller constraint, it is also possible to provide extra information to custom constraints with the meta: Option[Any] parameter.