I am trying to create a login feature for my apache tapestry website, where after logging in, instead of the 'Log In' and 'Register' button, the email of the logged user should be displayed, along with a 'Log Out' button.
Could anyone please tell how should this be implemented the best way?
I can't seem to figure out how should i detect if the user is logged in, in the frontend part, in order to display a different menu options (i am new in tapestry).
Best regards, Marius.
Authentication (of which login is a part) is very application specific. How you define a User (or do you call it a "Customer", for example) is not something the framework does.
Typically, you will have a SessionStateObject representing your User. You can then use something like this in your layout:
<t:if test="user">
<t:logoutLink/>
<p:else>
<t:signInForm/>
</t:if>
Again, components LogoutLink and SignInForm are for you to implement.
The user may be exposed from the Java code as:
#Property
#sessionState(create=false)
private User user;
This says that the user field is linked to a value stored in the HTTP session; further, the User will not be created when the field is first read; instead, your SignInForm component should assign to its user field.
After a little bit of research regarding this matter, i found the following approach:
1) I created an Authenticator interface
public interface Authenticator {
Users getLoggedUser();
boolean isLoggedIn();
void login(String email, String password) throws AuthenticationException;
void logout();
}
2) Also created an AuthenticatorImpl.java class that implements that interface
public class AuthenticatorImpl implements Authenticator {
public static final String AUTH_TOKEN = "authToken";
#Inject
private StartDAO dao;
#Inject
private Request request;
public void login(String email, String password) throws AuthenticationException
{
Users user = dao.findUniqueWithNamedQuery("from Users u where u.Email = '" + email + "' and u.Password = '" + password + "'");
if (user == null) { throw new AuthenticationException("The user doesn't exist"); }
request.getSession(true).setAttribute(AUTH_TOKEN, user);
}
public boolean isLoggedIn()
{
Session session = request.getSession(false);
if (session != null) { return session.getAttribute(AUTH_TOKEN) != null; }
return false;
}
public void logout()
{
Session session = request.getSession(false);
if (session != null)
{
session.setAttribute(AUTH_TOKEN, null);
session.invalidate();
}
}
public Users getLoggedUser()
{
Users user = null;
if (isLoggedIn())
{
user = (Users) request.getSession(true).getAttribute(AUTH_TOKEN);
}
return user;
}
}
3) Created the corresponding binding in the AppModule.java class
public static void bind(ServiceBinder binder)
{
binder.bind(StartDAO.class, StartDAOImpl.class);
binder.bind(Authenticator.class, AuthenticatorImpl.class);
}
4) And on my Layout.java page i used it in the following way
#Property
private Users user;
#Inject
private Authenticator authenticator;
void setupRender()
{
if(authenticator.getLoggedUser().getAccountType().equals("Administrator")){
administrator = authenticator.getLoggedUser();
}
user = authenticator.getLoggedUser();
}
Object onLogout(){
authenticator.logout();
return Login.class;
}
Layout.tml
<t:if test="user">
<span class="navbar-right btn navbar-btn" style="color: white;">
Welcome ${user.Name}! <a t:type="eventLink" t:event="Logout" href="#">(Logout)</a>
</span>
</t:if>
<t:if negate="true" test="user">
<span class="navbar-right">
<t:pagelink page="user/create" class="btn btn-default navbar-btn">Register</t:pagelink>
<t:pagelink page="user/login" class="btn btn-default navbar-btn">Sign in</t:pagelink>
</span>
</t:if>
This worked for me without any problems. Hope that it helps others.
Best regards, Marius.
Related
I have a login funcitonality in my application ,
where i am able to store the user in a session
and i am also able to stop user to signIn , if he is already Signed in on the same browser ..
But if a signedIn user tries to logIn again from a DIFFERENT browser i am not able to stop him .
here is the code..
I am using this
session=getThreadLocalRequest().getSession(true);
User loggedInUser = (User) session.getAttribute("user");
Now this loggedInUser have the user object if a loggedInUser tries to get in the application from the SAME browser in another tab (SO it works for me)
BUT this loggedInUser is null if a loggedInUser tries to get in the application from the DIFFERENT browser(SO its not working for me)
here is the code..
public User signIn(String userid, String password) {
String result = "";
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MySQLRdbHelper rdbHelper = (MySQLRdbHelper) ctx.getBean("ManagerTie");
User user = (User) rdbHelper.getAuthentication(userid, password);
if(user!=null)
{
session=getThreadLocalRequest().getSession(true);
User loggedInUser = (User) session.getAttribute("user");
if(loggedInUser != null && user.getId() == loggedInUser.getId()){
user.setId(0);
}else{
session=getThreadLocalRequest().getSession(true);
session.setAttribute("user", user);
}
}
return user;
I am using JAVA , GWT
Yes by storing static map on server side,Which stores User Id as a key and Session as value.
Here is working code from my bag directly.
class SessionObject implements HttpSessionBindingListener {
User loggedInUser;
Logger log = Logger.getLogger(SessionObject.class);
public SessionObject(User loggedInUser) {
this.loggedInUser=loggedInUser;
}
public void valueBound(HttpSessionBindingEvent event) {
LoggedInUserSessionUtil.getLogggedUserMap()
.put(loggedInUser, event.getSession());
return;
}
public void valueUnbound(HttpSessionBindingEvent event) {
try {
LoggedInUserSessionUtil.removeLoggedUser(loggedInUser);
return;
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
Java tip I followed and Java2s link while I developed.
I'm using Hibernate + JSF + PrimeFaces. Now I wanna update password of admin but I always get error dialog. I can't figure out what wrong in my code. Hope anyone suggest me.
loginBean (SessionScoped)
public class loginBean {
private Users username;
private UsersDao userdao;
/** Creates a new instance of loginBean */
public loginBean() {
userdao = new UsersDao();
username = new Users();
}
public Users getUsername() {
return username;
}
public void setUsername(Users username) {
this.username = username;
}
public void updateUser(){
String msg;
if(userdao.updateUser(username)){
msg = "Updated Successfully!";
}else{
msg = "Error. Please check again!";
}
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, null);
FacesContext.getCurrentInstance().addMessage(msg, message);
}
}
UserDAO.java
public class UsersDao {
public boolean updateUser(Users user){
boolean flag;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try{
session.beginTransaction();
session.save(user);
session.beginTransaction().commit();
flag = true;
}catch(Exception e){
flag = false;
session.beginTransaction().rollback();
}
return flag;
}
}
xhtml
<p:growl id="growl" showDetail="true" life="3000" />
<h:form id="tab">
<h:outputLabel>Password</h:outputLabel>
<h:inputSecret value="#{loginBean.username.password}" />
<p:commandButton id="loginButton" value="Login" update=":growl" ajax="false" action="#{loginBean.updateUser}"/>
</h:form>
You're actually performing a save operation into the Session, instead of an update one, that's why you've got a Violation of PRIMARY KEY exception. You're telling Hibernate to add a new user with the same credentials, which is constrained by the Data Base.
In addition, and unrelated to the concrete problem, you should change your Users class name to User, as it refers to a concrete user.
I have a login funcitonality in my application ,
where i am able to store the user in a session
and i am also able to stop user to signIn , if he is already Signed in on the same browser ..
But if a signedIn user tries to logIn again from a DIFFERENT browser i am not able to stop him .
here is the code..
I am using this
session=getThreadLocalRequest().getSession(true);
User loggedInUser = (User) session.getAttribute("user");
Now this loggedInUser have the user object if a loggedInUser tries to get in the application from the SAME browser in another tab (SO it works for me)
BUT this loggedInUser is null if a loggedInUser tries to get in the application from the DIFFERENT browser(SO its not working for me)
here is the code..
public User signIn(String userid, String password) {
String result = "";
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MySQLRdbHelper rdbHelper = (MySQLRdbHelper) ctx.getBean("ManagerTie");
User user = (User) rdbHelper.getAuthentication(userid, password);
if(user!=null)
{
session=getThreadLocalRequest().getSession(true);
User loggedInUser = (User) session.getAttribute("user");
if(loggedInUser != null && user.getId() == loggedInUser.getId()){
user.setId(0);
}else{
session=getThreadLocalRequest().getSession(true);
session.setAttribute("user", user);
}
}
return user;
I am using JAVA , GWT
Yes by storing static map on server side,Which stores User Id as a key and Session as value.
Here is working code from my bag directly.
class SessionObject implements HttpSessionBindingListener {
User loggedInUser;
Logger log = Logger.getLogger(SessionObject.class);
public SessionObject(User loggedInUser) {
this.loggedInUser=loggedInUser;
}
public void valueBound(HttpSessionBindingEvent event) {
LoggedInUserSessionUtil.getLogggedUserMap()
.put(loggedInUser, event.getSession());
return;
}
public void valueUnbound(HttpSessionBindingEvent event) {
try {
LoggedInUserSessionUtil.removeLoggedUser(loggedInUser);
return;
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
Java tip I followed and Java2s link while I developed.
I am writing a login page that when a invalid user tries to login I redirect to the login action with a error parameter equal to 1.
private String username;
private String password;
private int error;
#Override
public String execute()
{
//validate user input
if (username == null || password == null || username.isEmpty() || password.isEmpty())
{
error = 2;
return LOGIN;
}
LoginModel loginModel = new LoginModel(username, password);
HttpBuilder<LoginModel, User> builder = new HttpBuilder<LoginModel, User>(User.class);
builder.setPath("service/user/authenticate");
builder.setModel(loginModel);
IHttpRequest<LoginModel, User> request = builder.buildHttpPost();
User user = request.execute(URL.BASE_LOCAL);
//redirects to login page
if (user == null)
{
error = 1;
return LOGIN;
}
else
{
return SUCCESS;
}
}
//Getters/Setters
If a invalid user trys to login it redirects to localhost:8080/app/login.action?error=1. I am trying to display a error message to user by access the error parameter by using the if tag but its not working the message is not displaying.
<s:if test="error == 1">
<center>
<h4 style="color:red">Username or Password is invalid!!</h4>
</center>
What am I doing wrong?
As far as I'm concerned what you're doing wrong is completely ignoring the framework.
Roughly, IMO this should look more like this:
public class LoginAction extends ActionSupport {
private String username;
private String password;
#Override
public String validate() {
if (isBlank(username) || isBlank(password)) {
addActionError("Username or Password is invalid");
}
User user = loginUser(username, password);
if (user == null) {
addActionError("Invalid login");
}
}
public User loginUser(String username, String password) {
LoginModel loginModel = new LoginModel(username, password);
HttpBuilder<LoginModel, User> builder = new HttpBuilder<LoginModel, User>(User.class);
builder.setPath("service/user/authenticate");
builder.setModel(loginModel);
IHttpRequest<LoginModel, User> request = builder.buildHttpPost();
return request.execute(URL.BASE_LOCAL);
}
}
You would have an "input" result containing the form, and display any action errors present using whatever style you wanted. If it's critical to change the styling based on which type of login error it is you'd have to play a few more games, but that seems excessive.
Unrelated, but I'd move that loginUser code completely out of the action and into a utility/service class, but at least with it wrapped up in a separate method you can mock it more easily. It certainly does not belong in the execute method.
You need to provide the getter and setter of field 'error' to access it from value stack.
public int getError()
{
return error;
}
public void setError(int error)
{
this.error = error;
}
And try to access it in OGNL:
<s:if test="%{#error==1}"></s:if>
Or using JSTL:
<c:if test="${error==1}"></c:if>
I'm currently working on a (relatively) basic web application that functions as a time clock for a fictional employer. Currently, the application implements HTML, JavaScript, Java, MySQL, the Spring Framework and xml. I have a log in page, and it takes the user input for the Username and Password and stores the information. The problem is, I can't seem to figure out how to take that information and compare it with the MYSQL database to successfully log in. I can post examples of code, if necessary and thanks in advance for the assistance.
This is a piece of the LoginController:
#RequestMapping(value = "/jsp/login")
public ModelAndView existUser(HttpServletRequest request) {
return new ModelAndView("UserPrint.jsp", hashmap.makeHashMap());
}
#RequestMapping(value = "userLogin")
public ModelAndView loginUser(HttpServletRequest request,
HttpSession session) {
String strLoginJsp = "login.jsp";
String strSessionErrorAttribute = "errors";
User sessionUser = getUserFromSession(session);
if (request.getHeader("referer") == null
|| request.getHeader("referer").contains("AddNewUser.html")) {
session.setAttribute(SESSION_USER_ATTRIBUTE, new User());
session.setAttribute(strSessionErrorAttribute, "");
return new ModelAndView(strLoginJsp, hashmap.makeHashMap());
}
User requestUser = new User();
String requestedUserName = request.getParameter("userName");
requestUser.setUserName(requestedUserName);
String requestedPassword = request.getParameter("password");
requestUser.setPassword(requestedPassword);
session.setAttribute(strSessionErrorAttribute, "");
// Check if username and password is in DB
User loginUser = userDao.login(requestUser);
if (loginUser == null) {
// Either the username doesn't exist, or the password was bad.
if (userDao.userNameExist(requestedUserName)) {
// user entered bad password
if (sessionUser.getUserName() != null
&& sessionUser.getUserName().equals(
requestUser.getUserName())) {
} else {
sessionUser.setUserName(requestUser.getUserName());
}
}
} else {// username does not exist in db
session.setAttribute(strSessionErrorAttribute,
"Please register account.");
Here's a piece of the UserDao:
#SuppressWarnings("unchecked")
#Transactional
public List<User> getAllUsers() {
Query query = em.createNamedQuery("fetchAllUsers");
return query.getResultList();
}
public User login(User user) {
Query query = em.createNamedQuery("userLogin");
query.setParameter("userName", user.getUserName());
query.setParameter("password", user.getPassword());
List<User> currentUsers = query.getResultList();
if (currentUsers.size() > 0) {
return (User) currentUsers.get(0);
}
return null;
}
#SuppressWarnings("unchecked")
#Transactional
public Boolean userNameExist(String userName) {
Query query = em.createNamedQuery("getUserWithUsername");
query.setParameter("userName", userName);
List<User> existUser = query.getResultList();
if (existUser.size() > 0) {
return true;
}
return false;
}
To expand on dm03514 's answer - yes you should "sanitize" user input by using prepared statement objects in Java JDBC.
If you're using Spring then you should use spring-security. They have pretty much done this for you already and you just have to configure it.
Normally you would take your login and password and search for a user
String queryStr = "SELECT * FROM users WHERE login='"+sanitize(userLogin)+"' AND password='"+sanitize(userPass)"'";
This is not actual code just psuedo code. I do not know how java or spring handles sanitation but it is of utmost importance that you dont' trust anything input by the user when you are building a query string.
The idea is if this results in 1 user the user is valid, if it returns none the user is not valid!
Using paramaterized queries could be the best approach
Yes, please, post some code.
What exactly is the issue?
On the most basic level you should be able to:
pass the username and password as parameters in the HttpServletRequest object
Retrieve said parameters by "name" from the HSR object in the Controller.
Pass them to the SQL query for comparison against the database field.
Which of the above steps failed?