I like to know whats the correct way to create a login/logout mechanizm in jsf2 environment.
I have created a login xhtml form and a Admin bean that stores a static boolean (is_authenticated) . I want to check that variable in every xhtml page , if true? continue , else redirect to login page.
this is Admin.java bean:
#ManagedBean
#SessionScoped
public class Admin implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
static Boolean authenticated;
String username;
String password;
#PostConstruct
public void initialisation() { // init bean on new instance
Admin.authenticated = false;
}
public Boolean getAuthenticated(){
return Admin.authenticated;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String doLogout() {
Admin.authenticated=false;
return "login?faces-redirect=true";
}
public String validity() {
if(username.equals("admin") && password.equals("admin")) {
Admin.authenticated=true;
return "success";
} else {
Admin.authenticated=false;
return "failure";
}
}
}
and this is the main.xhtml:
<?xml version="1.0" encoding="UTF-8" ?>
<ui:composition template="template.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:define name="content">
<c:if test="#{admin.authenticated == false}">
// update Admin.authenticate to false
<meta http-equiv="refresh" content="0;URL=login.xhtml" />
</c:if>
<h1>Statistics</h1>
<div style="margin:10px">
<h:panelGrid columns="3">
Advertisers:
<h:outputText value="#{stats.advertisers}"/>
<h:outputText value=""/>
Publishers:
<h:outputText value="#{stats.publishers}"/>
<h:outputText value=""/>
Campaigns:
<h:outputText value="#{stats.campaigns}"/>
<h:outputText value="(#{stats.activeCampaigns} active)"/>
Banners:
<h:outputText value="#{stats.banners}"/>
<h:outputText value="(#{stats.activeBanners} active)"/>
Games:
<h:outputText value="#{stats.games}"/>
<h:outputText value="(#{stats.activeGames} active)"/>
</h:panelGrid>
</div>
</ui:define>
</ui:composition>
Two questions:
in the jstl 'if' ,I get : "Property 'authenticated' not found on
type com.pkg.name.Admin"
How can I update Admin.authenticate to false from the xhtml file(sorry for the lame question, i'm really new to jsf and web dev in general)
is it good practice to use this static variable? (like an instance of the session variable)
According to me the correct and cleaner way to implement login/logout is to create a filter and apply it to the urls that should be protected(e.g. /admin/*).
If the user sucessfully logs in load his details in session bean. When the user requests a protected page the filter runs first. In the filter get the session from request and call its getAttribute method to get the session bean(jsf stores the session scoped beans as session attributes). If you get the bean object then he is logged in else if you get null he is not authorized and you can redirect him to login page.
For logout you can just call invalidate on the session and all the session scoped attributes will be destroyed.
A working example will be like following:
The SessionScoped bean which will save login information:
UserBean.java
#ManagedBean
#SessionScoped
class UserBean implements Serializable{
private User user;
//getter/setter for user
}
LoginBean.java
#ManagedBean
class LoginBean
{
#ManagedProperty(value="#{userBean}")
private UserBean userBean;
public UserBean getUserBean(){
return userBean;
}
public void setUserBean(UserBean userBean){
this.userBean=userBean;
}
private String username,password;
//getter and setter for username,password
public String checkLogin(){
//check database for user
if(user!=null){
userBean.setUser(user);
}
//...
}
}
LoginFilter.java- We apply this filter to url pattern: /admin/*
#WebFilter("/admin/*")
class LoginFilter implements Filter{
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpSession session=((HttpServletRequest)request).getSession();
userBean userBean=(userBean)session.getAttribute("userBean");
if(userBean!=null){
User user=userBean.getUser();
if(user==null){
((HttpServletResponse)response).sendRedirect("login.jsf");
}
else
chain.doFilter(request, response);
}
else
((HttpServletResponse)response).sendRedirect("login.jsf");
}
public void init(FilterConfig fc){}
public void destroy(){}
}
login.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head><title>Login To Admin Panel</title>
</h:head>
<h:body>
<h:form>
Username : <h:inputText value="#{loginBean.username}"/>
Password : <h:inputSecret value="#{loginBean.password}"/>
<h:commandButton value="Login" action="#{loginBean.checkLogin}" />
</h:form>
</h:body>
</html>
For log out you can simply call session.invalidate() which will destroy the session along with any session scoped attributes.
This way you don't have to write conditional jstl tags to determine whether the use is logged in or not.
Hope this helps.
Related
i want use Primefaces BlockUI's widgetvar (at the moment i use a modal dialog for it). The application should block only when i select something (a long method will call) and unblock after complete. But it blocks the full side on first side access. Make i something wrong?
When i block the table specific it works. (block="table") But i want block the whole page.
Use Primefaces 5.1 & Mojarra 2.2.8
Short example:
xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>test</title>
</h:head>
<h:body>
<h:form>
<p:blockUI widgetVar="block" blocked="false"/>
<p:dataTable id="table" value="#{myController.tableItems}" rowKey="#{data}"
selection="#{myController.selectedItem}" selectionMode="Single"
var="data">
<p:ajax event="rowSelect" onstart="PF('block').show()"
listener="#{myController.doSomething}"
oncomplete="PF('block').hide()" />
<p:column>#{data}</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
Bean:
#ManagedBean
#ViewScoped
public final class MyController implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private List<String> tableItems;
private String selectedItem;
#PostConstruct
public void init() {
tableItems = new ArrayList<String>();
tableItems.add("test1");
tableItems.add("test2");
}
public void doSomething(SelectEvent event){
System.out.println("DO Something");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(String selectedItem) {
this.selectedItem = selectedItem;
}
public List<String> getTableItems() {
return tableItems;
}
public void setTableItems(List<String> tableItems) {
this.tableItems = tableItems;
}
}
Add an id attribute the body and use that in the block= attribute on the blockui component
JSF 2.1
Tomcat 7.0
Is this a wrong use of dependency injection?
It works ok moving around the page. But "it works" is not the same as "it's correct".
I would use this pattern also for search purpose. I have a request and i like to use it to populate a table in the same page. Is this possible?
index.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<link rel="SHORTCUT ICON" href= "resources/img/onlyT.ico"></link>
<title>title</title>
<h:outputStylesheet library="css" name="compass.css"/>
</h:head>
<h:body>
Login system
<br />
<h:form>
User : <h:inputText value="#{user.username}" />
Password : <h:inputSecret value="#{user.password}" />
<h:commandButton action="#{loginBean.performLogin()}" value="Submit" />
<h:commandButton value="reset" type="reset" />
<h:commandButton value="ChangePsW" action="changePassword"></h:commandButton>
</h:form>
<h:message for="" style="color:red;margin:8px;"/>
</h:body>
</html>
LoginBan.java
#ManagedBean
#RequestScoped
public class LoginBean {
#ManagedProperty(value="#{user}")
private UserBean userBean;
//must povide the setter method
public void setUserBean(UserBean userBean) {
this.userBean = userBean;
}
public LoginBean() {}
public String performLogin(){
//Mi connetto al db
if(userBean.getUsername().equalsIgnoreCase( "mario")){
//effettuo i controlli per stabilire se esiste l'utente
userBean.setRoles("-EE-E-E-E-E-E");
return "/mainPortal/mainPortal";
}
return "/mainPortal/index";
}
}
UserBean.java
#ManagedBean (name="user")
#SessionScoped
public class UserBean implements Serializable {
private String Username;
private String Password;
private String Roles;
/** Creates a new instance of UserBean */
public UserBean() {
}
/**
* #return the Username
*/
public String getUsername() {
return Username;
}
/**
* #param Username the Username to set
*/
public void setUsername( String Username ) {
this.Username = Username;
}
/**
* #return the Password
*/
public String getPassword() {
return Password;
}
/**
* #return the Roles
*/
public String getRoles() {
return Roles;
}
/**
* #param Roles the Roles to set
*/
public void setRoles( String Roles ) {
this.Roles = Roles;
}
/**
* #param Password the Password to set
*/
public void setPassword( String Password ) {
this.Password = Password;
}
change password also use the userBean and has his changePasswordBean.
JSF 2 allows you injecting managed beans in other managed beans. This is only limited by the scope of the bean you're actually injecting, which has to be greater than the scope of the bean you actually are in. I mean, you can inject #SessionScoped bean in a #ViewScoped one, but not in the other way. As you follow that convention, I think you're doing it well.
Generally, your application should be composed by #ViewScoped or #RequestScoped beans to handle current user input/outputs and wider scoped beans for session or application means. So, when user logs in, it's a good idea to maintain his data in a session context, however I suggest you not to maintain user's password into session, at least if you're not going to use it once the login has been succesfully done.
Finally the question you make about search requests, I think you can implement a search input in your page and make your result table load dinamically depending on the search. Just use ajax to obtain it without having to reload the whole page. You can implement everything in a #ViewScoped bean, but remember not to return navigation results in your listener methods if you want to maintain the bean working.
i have a datatable with one row , i need to edit the fields of this row so i have a few inputText with the values, but when i edit them and click on the commandbutton(that calls the method "actualizarUsuario" the values are passed as null.
this is my bean code:
#ManagedBean(name = "user")
#ViewScoped
public class userDetalles implements Serializable {
private Usuario u;
private usuarioController controlador;
Rol rol;
private long selection;
private long selectionrol;
Agrupacion agrupacion;
private Privilegio privilegio;
private RolController controladorRol;
private ControladorAgrupaciones controladorAgrup;
private String nombres;
private String apellidoP;
private String apellidoM;
private Boolean check;
#PostConstruct
public void init() {
rol= new Rol() ;
u=new Usuario();
agrupacion=new Agrupacion();
privilegio=new Privilegio();
controlador= new usuarioController();
controladorRol=new RolController();
controladorAgrup=new ControladorAgrupaciones();
Usuario u=new Usuario();
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
//Obtener parametros del request
Map<String, String> parameterMap = (Map<String, String>) externalContext.getRequestParameterMap();
long iduser = Long.valueOf(parameterMap.get("id_usuario"));
this.u=controlador.getUser(iduser);
}
public Usuario getU() {
return u;
}
public void setU(Usuario u) {
this.u = u;
}
public long getSelection() {
System.out.println("selection value----------->"+selection);
return selection;
}
public void setSelection(long selection) {
this.selection = selection;
}
public long getSelectionrol() {
return selectionrol;
}
public void setSelectionrol(long selectionrol) {
this.selectionrol = selectionrol;
}
public String getNombres() {
return nombres;
}
public void setNombres(String nombres) {
this.nombres = nombres;
}
public String getApellidoP() {
return apellidoP;
}
public void setApellidoP(String apellidoP) {
this.apellidoP = apellidoP;
}
public String getApellidoM() {
return apellidoM;
}
public void setApellidoM(String apellidoM) {
this.apellidoM = apellidoM;
}
public Boolean getCheck() {
return check;
}
public void setCheck(Boolean check) {
this.check = check;
}
public void actualizarUsuario(){
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
Map<String, String> parameterMap = (Map<String, String>) externalContext.getRequestParameterMap();
nombres=parameterMap.get("nombres");
apellidoP=parameterMap.get("apellidoP");
apellidoM=parameterMap.get("apellidoM");
check=Boolean.parseBoolean(parameterMap.get("check"));
//test
System.out.println(nombres+" "+apellidoP+" "+apellidoM+" "+check);
u.setNombres(nombres);
u.setApellidoPaterno(apellidoP);
u.setApellidoMaterno(apellidoM);
u.setActive(check);
controlador.saveUsuario(u);
}
}
and this is my view:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<div class="container">
<h:panelGroup id="Users">
<h:form id="Form">
<h2>Detalles Usuario</h2>
<h:dataTable id="users" value="#{user.u}" styleClass="table table-striped table-bordered" headerClass="sorting_asc"
rowClasses="odd,even">
<h:column>
<f:facet name="header">#</f:facet>
#{user.u.id}
</h:column>
<h:column>
<f:facet name="header">Identificador</f:facet>
<h:inputText id="identificador" value="#{user.u.identificador}" />
</h:column>
<h:column>
<f:facet name="header">Nombre</f:facet>
<h:inputText id="nombres" value="#{user.u.nombres}"/>
<h:inputText id="apellidoP" value="#{user.u.apellidoPaterno}"/>
<h:inputText id="apellidoM" value="#{user.u.apellidoMaterno}"/>
</h:column>
<h:column>
<f:facet name="header">Active</f:facet>
<h:selectBooleanCheckbox id="check" value="#{user.u.active}"></h:selectBooleanCheckbox>
</h:column>
</h:dataTable>
<h:commandButton value="Actualizar" type="submit" styleClass="btn-primary" actionListener="#{user.actualizarUsuario}">
</h:commandButton>
</h:form>
<script type="text/javascript" src="js/paging-bootstrap.js"></script>
<script type="text/javascript" src="js/contenidoc.datatable.init.js"></script>
</h:panelGroup>
</div>
</ui:composition>
Your concrete problem is caused because you used the wrong parameter names. Look in the generated HTML output and the HTTP traffic monitor for the right parameter names.
However, your actual problem is bigger: your view/model approach is completely wrong. You shouldn't be using a <h:dataTable> at all. It is intented for a collection of entities like List<User>, not for a single entity like User. You should be using <h:panelGrid>. You don't need to explode/flatten model properties in controller at all. You have those properties already in the model itself. You don't need to manually traverse the request parameter map. JSF will already do all the job for you.
I won't rewrite this mess for you, but to the point you should follow the following kickoff example:
Model:
public class User {
private Long id;
private String username;
private String firstname;
private String lastname;
// ...
// Autogenerate standard getters/setters.
}
Controller:
#ManagedBean
#ViewScoped
public class EditUser {
private User user; // Initialize it in postconstruct or as viewparam.
private UserService service; // Initialize it as #EJB or in postconstruct.
public void save() {
service.save(user); // That's all. Really.
}
public User getUser() {
return user;
}
// No other getters/setters! They are all already in User class.
}
View:
<h:panelGrid>
<h:inputText value="#{editUser.user.username}" />
<h:inputText value="#{editUser.user.firstname}" />
<h:inputText value="#{editUser.user.lastname}" />
<h:commandButton value="save" action="#{editUser.save}" />
</h:panelGrid>
That's all. See also among others this JSF 2.0 tutorial. As to your attempt to get the user by ID, you should rather use <f:viewParam>, see also What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for? and communication in JSF 2.0.
i am busy writing a very simple login page using JavaEE6, JSF 2.0 and CDI.
My login page looks as follows (some stuff is removed for clarity):
<html>
<head>
<title>HomeBase - Login</title>
</head>
<body>
<h3>Login</h3>
<h:form>
<div>
<label>UserID:</label>
<h:inputText value="#{loginBean.userid}" />
</div>
<div>
<label>Password:</label>
<h:inputSecret value="#{loginBean.password}" />
</div>
<h:commandButton value="Login" action="#{loginBean.login}" />
</h:form>
</body>
</html>
and the backingbean looks as follows:
#ManagedBean
#RequestScoped
public class LoginBean implements Serializable {
#Inject Logger LOG;
private String userid;
private String password;
public String login() {
LOG.info("Start login procedure.");
if ("gast".equalsIgnoreCase(userid) && "gast".equals(password)) {
SessionBean sessionBean = (SessionBean) FacesContext.getCurrentInstance()
.getExternalContext().getSessionMap().get("sessionBean");
User user = new User();
user.setUserid(userid);
user.setPassword(password);
user.setUsername("Gast");
sessionBean.setUser(user);
return "loginSuccess";
}
return "loginFailure";
}
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Now when i call the loginpage it gets correctly displayed. Both inputfields are empty. When in debugmode, i can see the getters for both fieldvalues are getting called. Next, i fill in the fields and press the submit button and an immediate nullpointer exception occurs. Clearly the LoginBean is instatiated the first time (when the page is displayed), but NOT when i press the commandbutton.
What happend?
The CDI #Inject doesn't work in a JSF #ManagedBean. Hence LOG remains null.
Use CDI #Named instead of JSF #ManagedBean and make sure that you import #RequestScoped annotation from CDI javax.enterprise.context package instead of JSF javax.faces.bean.
This is kind of an extension to the question
Navigate to external URL from a backing bean?
I need to invalidate the session in the backing bean method and then forward to an external URL. The outputLink component does not have the capability to invoke an action method (logout method of the bean in this case).
If I use commandLink, the action method gets invoked but after the session is invalidated, another session is created before forwarding to the external URL.
To be more specific: I have a view that loads a list of items on the home page. The home page has a bunch of links (one of them being the logout image/button) on the top that come from a template xhtml. In the template xhtml file, I have the commandLink code that invokes the logout method of the LogoutBean.java. The method gets invoked fine as expected, BUT when I put a break point in the PostConstruct method of the HomeBean, I see that this method is invoked after invalidating the session and then it forwards to the external URL. How to prevent this?
Code:
template.xhtml:
<h:form>
<p:panel id="HomeHeaderPanel" styleClass="tableheaderfont" style="width:98%">
<h:panelGrid id="filterGrid" columns="2" cellpadding="0" styleClass="normalfont" style="width: 98%" columnClasses="leftalign,rightalign">
<h:panelGroup>
<h:link outcome="reviewHome.xhtml?faces-redirect=true" id="homeLink"
title="Review Home">
<h:graphicImage value="images/home_small.png" id="homeIcon" alt="Review Home"/>
</h:link>
<p:spacer width="5"/>
<h:commandLink action="#{logoutBean.logout}" >
<h:graphicImage value="images/logout_small.png" id="logoutIcon" alt="Logout" title="Logout"/>
</h:commandLink>
</h:panelGroup>
</h:panelGrid>
</p:panel>
</h:form>
reviewHome.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui">
<f:view contentType="text/html">
<ui:composition template="template.xhtml">
<ui:define name="content">
<h:form styleClass="form" id="ptpReviewForm">
<f:event listener="#{homeBean.refresh}" type="preRenderView" />...content here...
</h:form>
</ui:define>
</ui:composition>
</f:view>
</html>
HomeBean.java:
#ManagedBean
#SessionScoped
public class HomeBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 3303546811067129792L;
public HomeBean(){}
#EJB
private ReviewEJB reviewEJB;
private List<HomeObject> homeList;
#SuppressWarnings("unused")
#PostConstruct
private void populateItpList()
{
logger.debug("In the PostConstruct method");
homeList = reviewEJB.getList();
}
//This method is loaded every time the Review Home view loads (prerenderView event)
public void refresh()
{
String refresh = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("refresh");
if(null != refresh && refresh.equalsIgnoreCase("true"))
{
homeList = reviewEJB.getList("another");
}
}
LogoutBean.java:
#ManagedBean
#SessionScoped
public class LogoutBean {
public void logout() throws ServletException
{
try {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
((HttpServletRequest) ec.getRequest()).logout();
HttpSession session = (HttpSession) ec.getSession(false);
// invalidate session
if (session != null) {
session.invalidate();
}
ec.redirect("/anotherWebAppContext/forward.jsp?link=review");
} catch (IOException e) {
e.printStackTrace();
}
}
That's caused by the <f:event type="preRenderView"> and the behaviour is fully specified.
Basically you want to kill that event. I've never tried it in this construct, so I can't tell from experience if it works, but you could try to get the events by UIViewRoot#getViewListenersForEventClass() and then clear it out before redirecting.
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
viewRoot.getViewListenersForEventClass(PreRenderViewEvent.class).clear();
// ...
That should in theory work.