Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Render JSF component based on user role

Tags:

jsf

jsf-2

How do I render JSF components based on a logged in user's role? I know the external context exposes the principals, but how should I do the rendering properly in JSF? In JSP it would be something like

<% isUserInRole(Roles.ADMIN) { %>
<button>Edit!</button>
<% } %>

How do I write this in JSF the best possible way? My best guess is the rendered attribute tied to a backing bean's method that returns a boolean, but that would introduce an irrelevant backing bean if I have to render some navigation items only for admins...

Glassfish V3.1, JSF 2.x

like image 259
9 revs Avatar asked Jan 20 '11 12:01

9 revs


2 Answers

If your web.xml is declared as Servlet 3.0 (which implicitly relates to JSP/EL 2.2)

<?xml version="1.0" encoding="UTF-8"?>
<web-app 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
    version="3.0">

then you can take benefit of being able to invoke methods with arguments in EL like as ExternalContext#isUserInRole():

rendered="#{facesContext.externalContext.isUserInRole('ADMIN')}"

Note that this requires a Servlet 3.0 capable container, but since you're using Glassfish 3 (which supports Servlet 3.0), it should work without any issues.

Also note that if you're using Facelets instead of JSP, then you've the HttpServletRequest available as #{request} in EL, allowing you the following shorter expression:

rendered="#{request.isUserInRole('ADMIN')}"
  • Conditionally displaying JSF components
  • Conditional rendering of non-JSF components (plain vanilla HTML and template text)
  • JSF: How control access and rights in JSF?
like image 170
BalusC Avatar answered Oct 05 '22 18:10

BalusC


In response to @wasimbhalli, there are two reasons I have found that the expression would always return false:

  1. The role name is case sensitive. rendered="#{facesContext.externalContext.isUserInRole('ADMIN')}" may return false, but try rendered="#{facesContext.externalContext.isUserInRole('admin')}", or rendered="#{facesContext.externalContext.isUserInRole('Admin')}".

  2. You have to define your roles in both web.xml (or as annotations) and map it in glassfish-web.xml.

The following is how to specify a role in web.ml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <security-role>
    <role-name>admin</role-name>
  </security-role>
</web-app>

The following is how to map the authentication group to the role in glassfish-web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
  <security-role-mapping>
    <role-name>admin</role-name> <!-- name defined in web.xml or annotations -->
    <group-name>admin</group-name><!-- name from authentication mechanism -->
  </security-role-mapping>
</glassfish-web-app>

In my testing it was necessary to do the mapping even when the names were the same, as I show in my example code. Also in my testing, I tried to only define the mapping and only to define the role in web.xml, and neither worked. I needed both, as specifying the role name in the correct case.

like image 41
pgreen2 Avatar answered Oct 05 '22 18:10

pgreen2