1.简介
用户登录模块,指的是根据用户输入的用户名和密码,对用户的身份进行验证等。如果用户没有登录,用户就无法访问其他的一些jsp页面,甚至是action都不能访问。
二、简单设计及实现
本程序是基于Java的SSH框架进行的。
1.数据库设计
我们应该设计一个用户表,其Userinfo表,对应的SQL语句为(Oracle数据库):
create table userinfo ( id varchar2(36) primary key, username varchar2(50) not null, password varchar2(50) not null, auth_limit varchar2(10) not null, register_time varchar2(40), create_time varchar2(40), remarks varchar2(1024) );
分别是id,也就是UUID,用户名、密码、权限、注册时间、记录插入数据库的时间、备注等几个字段。
2.使用MyEclipse的Hibernate逆向工具,生成对应的Java Bean和相应的hibernate的xml配置文件Userinfo.hbm.xml
package edu.njupt.zhb.bean; /** * Userinfo entity. @author MyEclipse Persistence Tools */ public class Userinfo implements java.io.Serializable { // Fields private String id; private String username; private String password; private String authLimit; private String registerTime; private String createTime; private String remarks; // Constructors /** default constructor */ public Userinfo() { } /** minimal constructor */ public Userinfo(String id, String username, String password, String authLimit) { this.id = id; this.username = username; this.password = password; this.authLimit = authLimit; } /** full constructor */ public Userinfo(String id, String username, String password, String authLimit, String registerTime, String createTime, String remarks) { this.id = id; this.username = username; this.password = password; this.authLimit = authLimit; this.registerTime = registerTime; this.createTime = createTime; this.remarks = remarks; } // Property accessors public String getId() { return this.id; } public void setId(String id) { this.id = id; } public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } public String getAuthLimit() { return this.authLimit; } public void setAuthLimit(String authLimit) { this.authLimit = authLimit; } public String getRegisterTime() { return this.registerTime; } public void setRegisterTime(String registerTime) { this.registerTime = registerTime; } public String getCreateTime() { return this.createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public String getRemarks() { return this.remarks; } public void setRemarks(String remarks) { this.remarks = remarks; } }
3.新建一个UserInfoService接口
/* * $filename: VideoInfoService.java,v $ * $Date: 2014-1-2 $ * Copyright (C) ZhengHaibo, Inc. All rights reserved. * This software is Made by Zhenghaibo. */ package edu.njupt.zhb.service; import edu.njupt.zhb.bean.Userinfo; /* *@author: ZhengHaibo *web: http://blog.csdn.net/nuptboyzhb *GitHub https://github.com/nuptboyzhb *mail: [email protected] *2014-1-2 Nanjing,njupt,China */ public interface UserInfoService { String getUserInfoList(int page, int rows); String addUser(Userinfo userinfo); String deleteUser(String userId); String editUser(Userinfo userinfo); Userinfo getUserInfoByName(String username); }
4.新建一个UserInfoServiceImpl类
/* * $filename: VideoInfoServiceImpl.java,v $ * $Date: 2014-1-2 $ * Copyright (C) ZhengHaibo, Inc. All rights reserved. * This software is Made by Zhenghaibo. */ package edu.njupt.zhb.service.impl; import java.util.ArrayList; import java.util.List; import net.sf.json.JSONObject; import edu.njupt.zhb.bean.Userinfo; import edu.njupt.zhb.dao.BaseDao; import edu.njupt.zhb.service.UserInfoService; import edu.njupt.zhb.utils.DataGrid; import edu.njupt.zhb.utils.Tips; import edu.njupt.zhb.view.ViewUser; /* *@author: ZhengHaibo *web: http://blog.csdn.net/nuptboyzhb *GitHub https://github.com/nuptboyzhb *mail: [email protected] *2014-1-2 Nanjing,njupt,China */ public class UserInfoServiceImpl implements UserInfoService{ private BaseDao<Userinfo> userinfoBaseDao; public BaseDao<Userinfo> getUserBaseDao() { return userinfoBaseDao; } public void setUserBaseDao(BaseDao<Userinfo> userinfoBaseDao) { this.userinfoBaseDao = userinfoBaseDao; } @Override public String getUserInfoList(int page, int rows) { // TODO Auto-generated method stub System.out.println("page="+page+",rows="+rows); String hql = "from Userinfo"; try { List<Userinfo> list = userinfoBaseDao.find(hql,page,rows); List<ViewUser> resultList = new ArrayList<ViewUser>(); for(Userinfo userinfo:list){ ViewUser viewUser = new ViewUser(); viewUser.setBz(userinfo.getRemarks()); viewUser.setId(userinfo.getId()); viewUser.setPwd(userinfo.getPassword()); viewUser.setYhm(userinfo.getUsername()); viewUser.setYhqx(userinfo.getAuthLimit()); viewUser.setZcsj(userinfo.getRegisterTime()); resultList.add(viewUser); } DataGrid<ViewUser> dataGrid = new DataGrid<ViewUser>(); dataGrid.setRows(resultList); dataGrid.setTotal(userinfoBaseDao.total(hql)); String result = JSONObject.fromObject(dataGrid).toString(); return result; } catch (Exception e) { e.printStackTrace(); return null; } } public String addUser(Userinfo userinfo) { // TODO Auto-generated method stub Tips tips = new Tips(); String hql = "from Userinfo where username = '"+userinfo.getUsername()+"'"; try { List<Userinfo> list = userinfoBaseDao.find(hql); if(list!=null&&list.size()>0){ tips.setMsg("添加失败!用户名已经存在!"); return JSONObject.fromObject(tips).toString(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } try { userinfoBaseDao.save(userinfo); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); tips.setMsg("添加失败"); return JSONObject.fromObject(tips).toString(); } tips.setMsg("添加成功"); return JSONObject.fromObject(tips).toString(); } public String deleteUser(String userid) { // TODO Auto-generated method stub Tips tips = new Tips(); try { userinfoBaseDao.executeHql("delete from Userinfo where id = '"+userid+"'"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); tips.setMsg("删除失败"); return JSONObject.fromObject(tips).toString(); } tips.setMsg("删除成功"); return JSONObject.fromObject(tips).toString(); } public String editUser(Userinfo userinfo) { // TODO Auto-generated method stub Tips tips = new Tips(); String hql = "from Userinfo where username = '"+userinfo.getUsername()+"'"; try { List<Userinfo> list = userinfoBaseDao.find(hql); if(list!=null&&list.size()>0){ tips.setMsg("更新失败!用户名已经存在!"); return JSONObject.fromObject(tips).toString(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } try { userinfoBaseDao.update(userinfo); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); tips.setMsg("编辑失败"); return JSONObject.fromObject(tips).toString(); } tips.setMsg("编辑成功"); return JSONObject.fromObject(tips).toString(); } @Override public Userinfo getUserInfoByName(String username) { // TODO Auto-generated method stub Userinfo userinfo = null; String hql = "from Userinfo where username = '"+username+"'"; try { List<Userinfo> list = userinfoBaseDao.find(hql); if(list == null || list.size()==0){ return null; } userinfo = list.get(0); return userinfo; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
5.新建UserInfoAction类,(当然,我们的BaseAction肯定是从struts2中的ActionSupport派生出来的)
/* * $filename: VideoInfoAction.java,v $ * $Date: 2014-1-2 $ * Copyright (C) ZhengHaibo, Inc. All rights reserved. * This software is Made by Zhenghaibo. */ package edu.njupt.zhb.action; import java.util.UUID; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import edu.njupt.zhb.bean.Userinfo; import edu.njupt.zhb.service.UserInfoService; import edu.njupt.zhb.utils.Tips; import edu.njupt.zhb.utils.TipsMsg; import edu.njupt.zhb.utils.Utils; /* *@author: ZhengHaibo *web: http://blog.csdn.net/nuptboyzhb *GitHub https://github.com/nuptboyzhb *mail: [email protected] *2014-1-2 Nanjing,njupt,China */ public class UserInfoAction extends BaseAction { /** * */ private static final long serialVersionUID = 3321845277376234101L; private Userinfo userinfo; private String userId; private String username; private String password; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public Userinfo getUserinfo() { return userinfo; } public void setUserinfo(Userinfo userinfo) { this.userinfo = userinfo; } private UserInfoService userInfoService; public UserInfoService getUserInfoService() { return userInfoService; } public void setUserInfoService(UserInfoService userInfoService) { this.userInfoService = userInfoService; } public void getUserInfoList() { String jsonResult = userInfoService.getUserInfoList(page, rows); System.out.println(jsonResult); super.writeStr(jsonResult); } /** * 添加用户 * * @return */ public void addUser() { if (userinfo == null) { Tips tips = new Tips(); tips.setMsg("添加失败!对象为空"); getPrintWriter().write(JSONArray.fromObject(tips).toString()); return; } userinfo.setId(UUID.randomUUID() + ""); userinfo.setCreateTime(Utils.getNowTime()); String jsonResult = userInfoService.addUser(userinfo); getPrintWriter().write(jsonResult); } /** * 删除用户 * * @return */ public void deleteUser() { if (userId == null) { Tips tips = new Tips(); tips.setMsg("删除失败!学号无效"); getPrintWriter().write(JSONArray.fromObject(tips).toString()); return; } String jsonResult = userInfoService.deleteUser(userId); getPrintWriter().write(jsonResult); } /** * 编辑用户 * * @return */ public void editUser() { if (userinfo == null) { Tips tips = new Tips(); tips.setMsg("编辑失败!对象为空"); getPrintWriter().write(JSONArray.fromObject(tips).toString()); return; } userinfo.setId(userId); String jsonResult = userInfoService.editUser(userinfo); getPrintWriter().write(jsonResult); } public void login() { TipsMsg tipsMsg = new TipsMsg(); if(username==null){ tipsMsg.setId("1"); tipsMsg.setMsg("用户名为空!"); String result = JSONObject.fromObject(tipsMsg).toString(); super.writeStr(result); return; } Userinfo userinfo = userInfoService.getUserInfoByName(username); if(userinfo==null){ tipsMsg.setId("1"); tipsMsg.setMsg("用户名不存在"); String result = JSONObject.fromObject(tipsMsg).toString(); super.writeStr(result); return; } if(!userinfo.getPassword().equals(password)){ tipsMsg.setId("1"); tipsMsg.setMsg("用户名或密码错误"); String result = JSONObject.fromObject(tipsMsg).toString(); super.writeStr(result); return; } super.setCurrentUser(userinfo); tipsMsg.setId("2"); tipsMsg.setMsg("登录成功"); String result = JSONObject.fromObject(tipsMsg).toString(); super.writeStr(result); return; } }
6.配置Spring的applicationContext.xml文件,依次注入Dao、Service和Action。
<bean id="baseDao" class="edu.njupt.zhb.dao.BaseDao"> <property name="sessionFactory" ref="sessionFactory"></property> </bean>
<bean id="userInfoService" class="edu.njupt.zhb.service.impl.UserInfoServiceImpl"> <property name="userBaseDao" ref="baseDao"></property> </bean>
<bean id="userInfoAction" class="edu.njupt.zhb.action.UserInfoAction" scope="prototype"> <property name="userInfoService" ref="userInfoService"></property> </bean>
7.配置Spring的Hibernate的Java Bean的映射文件
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop> <prop key="current_session_context_class">thread</prop> </props> </property> <property name="mappingResources"> <list> ... <value>edu/njupt/zhb/bean/Userinfo.hbm.xml</value> </list> </property> </bean>
8.配置Struts2文件,增加相应的Action,login等
<action name="getUserInfoList" class="userInfoAction" method="getUserInfoList"></action> <action name="addUser" class="userInfoAction" method="addUser"></action> <action name="deleteUser" class="userInfoAction" method="deleteUser"></action> <action name="editUser" class="userInfoAction" method="editUser"></action> <action name="login" class="userInfoAction" method="login"></action>
9.登录页面login.jsp中的ajax请求:
$("#btnLogin").click(function(){ var message = ""; var userName=$('input[name="userName"]').val(); var userPass=$('input[name="userPass"]').val(); if(userName == ""){ alert("请输入用户名!"); return; }else if(userPass == ""){ alert("请输入密码!"); return; } $.ajax({ type:"post", url:'login.action?username='+userName+'&password='+userPass, dateType:"json", success:function(data){ var json=eval("("+data+")"); if(json.id=='1'){ alert(json.msg); return; }else{ $("#frm").submit(); } } }); });
10.为了防止用户在不登陆的情况下,访问其他页面,我们在每一个jsp页面中添加如下代码:
<%if(null == request.getSession().getAttribute("user")){ response.getWriter().write("<script>window.location.href = 'login.jsp'</script>"); } %>
思考:
完成上述复杂的功能之后,我们是不是就完成任务了呢?显然不是,我们经过测试我们就会发现,在我们没有登录的情况下,我们确实没有办法访问其他的JSP页面,但是我们可以直接在浏览器中访问struts中配置的action!这依然有很大的漏洞,那我们怎么对action进行拦截呢?也即是对非login.action进行拦截判断,如果用户已经登录,就正常登录,如果用户没有登录,就返回login,让其登录。因此我们需要使用struts2的拦截器。
11.拦截器的Java代码
/* * $filename: CheckLoginInterceptor.java,v $ * $Date: 2014-1-15 $ * Copyright (C) ZhengHaibo, Inc. All rights reserved. * This software is Made by Zhenghaibo. */ package edu.njupt.zhb.utils; import java.util.Map; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import edu.njupt.zhb.action.UserInfoAction; import edu.njupt.zhb.bean.Userinfo; /* *@author: ZhengHaibo *web: http://blog.csdn.net/nuptboyzhb *GitHub https://github.com/nuptboyzhb *mail: [email protected] *2014-1-15 Nanjing,njupt,China */ public class CheckLoginInterceptor extends AbstractInterceptor{ /** * */ private static final long serialVersionUID = 2092930262572782343L; @Override public String intercept(ActionInvocation actionInvocation) throws Exception { // TODO Auto-generated method stub //System.out.println("begin check login interceptor!"); // 对LoginAction不做该项拦截 Object action = actionInvocation.getAction(); if (action instanceof UserInfoAction) { //System.out.println("exit check login, because this is login action."); //UserInfoAction userinfoAction = (UserInfoAction)action; return actionInvocation.invoke(); } // 确认Session中是否存在User Map<String,Object> session = actionInvocation.getInvocationContext().getSession(); Userinfo user = (Userinfo) session.get("user"); if (user != null) { // 存在的情况下进行后续操作。 //System.out.println("already login!"); return actionInvocation.invoke(); } else { // 否则终止后续操作,返回LOGIN System.out.println("no login, forward login page!"); return "login"; } } }
12.拦截器在Struts2中的配置
<interceptor name="loginIntercepter" class="edu.njupt.zhb.utils.CheckLoginInterceptor"> </interceptor> <!-- 拦截器栈 --> <interceptor-stack name="loginStack"> <interceptor-ref name="defaultStack" /> <interceptor-ref name="loginIntercepter" /> </interceptor-stack>
为每一个action配置拦截器,比如:
<action name="getStudentList" class="dataGridDemoAction" method="getStudentList"> <result type="httpheader"></result> <interceptor-ref name="loginStack" /> <result name="login">/login.jsp</result> </action> <action name="addStudent" class="dataGridDemoAction" method="addStudent"> <result type="httpheader"></result> <interceptor-ref name="loginStack" /> <result name="login">/login.jsp</result> </action> <action name="deleteStudent" class="dataGridDemoAction" method="deleteStudent"> <result type="httpheader"></result> <interceptor-ref name="loginStack" /> <result name="login">/login.jsp</result> </action> <action name="editStudent" class="dataGridDemoAction" method="editStudent"> <result type="httpheader"></result> <interceptor-ref name="loginStack" /> <result name="login">/login.jsp</result> </action>
当然,对于用户登录的action,我们也配置相应的拦截器:
<!-- 用户信息Action --> <action name="getUserInfoList" class="userInfoAction" method="getUserInfoList"> <interceptor-ref name="loginStack" /> <result name="login">/login.jsp</result> </action> <action name="addUser" class="userInfoAction" method="addUser"> <interceptor-ref name="loginStack" /> <result name="login">/login.jsp</result> </action> <action name="deleteUser" class="userInfoAction" method="deleteUser"> <interceptor-ref name="loginStack" /> <result name="login">/login.jsp</result> </action> <action name="editUser" class="userInfoAction" method="editUser"> <interceptor-ref name="loginStack" /> <result name="login">/login.jsp</result> </action> <action name="login" class="userInfoAction" method="login"> <interceptor-ref name="loginStack" /> </action>
总结:
以上步骤完成之后,我们基本上就完成了一个简单的用户登录模块的设计和实现了。而且我们可以根据用户的权限,显示不同的内容。比如管理员和普通操作员等具有不同的操作权限。
说明:
以上代码只是一些代码片段,我这里主要介绍的是思路。以上代码还有一些小小的漏洞,比如,我们在没有登录的情况下,还是可以直接访问getUserinfoList、deleteUser、editUser等与login在同一个Action类中的action。因此,我们设计的时候,要尽量将login和logout单独一个action。还有:上面写的getUserinfoList等一些action,目的是管理员对用户表进行增删改查等操作的,和本博客关系不大。本文主要注意的是:一个是在jsp页面中对未登陆用户的拦截,还有就是通过配置Struts2的拦截器,对未登录用户直接访问action方式进行拦截的。