1 用户认证
1.1 什么是用户认证
用户身份认证,是要解决这样的问题:用户告诉系统“我是谁”,系统就问用户凭什么证明你就是“谁”呢?对于采用用户名、密码验证的系统,那么就是出示密码。当用户名和密码匹配,则证明当前用户是谁;对于采用指纹等系统,则出示指纹;对于硬件Key等刷卡系统,则需要刷卡。
静态密码
用户名对应的密码设置在系统,以设置后一般不再改变,安全性低容易被木马窃取,可以定期修改密码,但不容易记忆。
动态密码
现在最常见的短信密码就是动态密码的一种方式。每次都生成一个动态密码,安全性较高。
验证码
验证码不是用户认证的方式,只是通常在用户登录时使用验证码方式。
是一种区分用户是计算机还是人的公共全自动程序。可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试,实际上用验证码是现在很多网站通行的方式(比如招商银行的网上个人银行,百度社区),我们利用比较简易的方式实现了这个功能。
1.2 用户授权
给用户分配操作权限,用户认证通过后,操作指定权限的功能。
用户授权通过数据模型:
用户表、角色表、权限表(细化到操作链接)、用户角色关系表、角色权限关系表。
企业中在实现用户授权功能时,通常对上边通过数据模型进行修改。
本系统对权限表进行扩展:菜单表(模块表)、操作表(操作链接)
1.3 用户认证实现流程
本系统采用用户名密码认证方法。
第一步:用户访问系统
第二步:系统对用户访问资源校验,该用户是否通过认证
如果用户已经认证,放行,用户继续操作。
如果用户没有认证,如果访问的是公开资源地址(无需认证即可访问),系统就放行,用户继续操作
如果用户没有认证,如果访问的不是公开资源地址,拦截,跳转登陆页面
第三步:用户进入登陆页面
如果用户没有认证,如果访问的不是公开资源地址,拦截,跳转登陆页面
第四步:用户输入用户名、密码进行身份认证
如果认证通过进入系统首页
如果认证不通过进入登陆页面。
认证过程:根据用户账号和密码进行认证。
1.4 用户认证实现
用户登陆功能实现。
登陆页面上要有验证码:随机产生代码,将代码存入session。
validatecode.jsp(验证码jsp)
随机产生代码存入session:
String session_code =(String) session.getAttribute("validateCode");
Service:
接口功能:校验用户身份信息
接口参数:用户账号、用户密码
接口返回值:用户身份信息
定义activeuser po 类作为用户身份信息对象Service
参数 密码 用户名 返回 用户身份信息
创建一个身份信息类 ActiveUser (考入)
实现序列化接口 tomcat在启动的时候会有反序列化将用户信息序列化到磁盘不是内存,有时候启动完tomcat后就不用登陆了就把信息反序列化了所以要实现序列化接口
* 用户身份信息,存入session
* 由于tomcat将session会序列化在本地硬盘上,所以使用Serializable接口
*
*/
publicclassActiveUser implementsjava.io.Serializable {
private Stringuserid;//用户账号
private Stringusername;//用户名称
private Stringgroupid;//用户类型
private Stringgroupname;//用户类型名称
private Menumenu;//操作菜单
private List<Operation>operationList;//操作权限,包括用户点击菜单及操作菜单功能所有链接权限
private Stringsysid;//用户所属单位id
private Stringsysmc;//单位名称
校验用户身份信息service:
// 通过账号密码校验用户信息登陆
@Override
public ActiveUsercheckUserInfo(String userid, String pwd)throws Exception {
//校验用户是否存在
Sysusersysuser = this.findSysuserByuserid(userid);
if (sysuser ==null) {
ResultUtil.throwExcepion(ResultUtil.createFail(Config.MESSAGE, 101,
null));
}
//校验密码合法性
Stringsyspwd = sysuser.getPwd();
Stringpwd_md5 = newMD5().getMD5ofStr(pwd);
//不区分大小写的密码校验,因为MD5加密大小写不一致
if(!syspwd.equalsIgnoreCase(pwd_md5)) {
ResultUtil.throwExcepion(ResultUtil.createFail(Config.MESSAGE, 114,
null));
}
//构建ActiveUser用户身份信息
ActiveUseractiveUser = newActiveUser();
activeUser.setUserid(userid);
activeUser.setUsername(sysuser.getUsername());
activeUser.setGroupid(sysuser.getGroupid());
activeUser.setSysid(sysuser.getSysid());
activeUser.setSysmc(this.findSysMc(sysuser.getGroupid(),
sysuser.getSysid()));//单位名称
return activeUser;
}
Action : 校验验证码 将用户身份信息写入session
@Controller
public classLoginAction {
@Autowired
private UserService userService;
// 用户登录页面
@RequestMapping("/login")
public String login(Modelmodel) throwsException {
return "/base/login";
}
// 用户提交方法
@RequestMapping("/loginsubmit")
public @ResponseBody
SubmitResultInfologinsubmit(HttpSession session, String userid,
Stringpwd, String validateCode) throws Exception {
// 验证码校验
Stringsession_code = (String) session.getAttribute("validateCode");
if(session_code!=null&&!session_code.equals(validateCode))
{
//验证码错误
ResultUtil.throwExcepion(ResultUtil.createFail(Config.MESSAGE, 113, null));
}
// 用户认证
ActiveUseractiveUser=userService.checkUserInfo(userid,pwd);
// 将用户信息写入session
session.setAttribute(Config.ACTIVEUSER_KEY,activeUser);
// 欢迎xx 用户登录
return ResultUtil.createSubmitResult(ResultUtil.createSuccess(
Config.MESSAGE, 107, new Object[] { "" }));
}
@RequestMapping("/logout")
public String logout(HttpSession session)throws Exception{
//session 过期
session.invalidate();
return "redirect:login.action";
}
}
页面:
login.jsp
关于表单校验:
在预加载方法设置表单的校验规则:
$(document).ready(function(){
//*****************表单校验******************
$.formValidator.initConfig({
formID : "loginform",
mode:'AlertTip',
onError : function(msg) {
alert(msg);
},
onAlert : function(msg) {
alert(msg);
}
});
$("#userid").formValidator({
onShow : "",
onCorrect:" "
}).inputValidator({
min : 1,
onError:"请输入用户名"
});
$("#password").formValidator({
onShow : "",
onCorrect:" "
}).inputValidator({
min : 1,
onError:"请输入密码"
});
$("#randomcode").formValidator({
onShow : "",
onCorrect:" "
}).inputValidator({
min : 1,
onError:"请输入验证码"
});
//*****************表单校验******************
});
使用AJAX的form提交用户账号和密码及验证码
//校验表单输入
functioncheckinput() {
//return$('#loginform').form('validate');
return$.formValidator.pageIsValid();
}
//登录提示方法
functionloginsubmit() {
//if(checkinput()){//校验表单,如果校验通过则执行jquerySubByFId
//ajax form提交
jquerySubByFId('loginform',login_commit_callback,null,'json');
//}
}
//登录提示回调方法
functionlogin_commit_callback(data) {
message_alert(data);
vartype = data.resultInfo.type;
if(1 == type) {//如果登录成功,这里1秒后执行跳转到首页
setTimeout("tofirst()", 1000);
} else{
//登录错误,重新刷新验证码
randomcode_refresh();
}
}
//刷新验证码
//实现思路,重新给图片的src赋值,后边加时间,防止缓存
functionrandomcode_refresh() {
$("#randomcode_img").attr('src',
'${baseurl}validatecode.jsp?time' +new Date().getTime());
}
//回首页
functiontofirst(){
//window.location='${baseurl}first.action';
if(parent.parent.parent){
//让最外层页面执行跳转
parent.parent.parent.location='${baseurl}first.action';
}else if(parent.parent){
parent.parent.location='${baseurl}first.action';
}else if(parent){
parent.location='${baseurl}first.action';
}else{
window.location='${baseurl}first.action';
}
}
详细参考下边的目录中demo。
如果登陆成功跳转首页
否则刷新验证码。
//登录提示回调方法
functionlogin_commit_callback(data) {
message_alert(data);
vartype = data.resultInfo.type;
if(1 == type) {//如果登录成功,这里1秒后执行跳转到首页
setTimeout("tofirst()", 1000);
} else{
//登录错误,重新刷新验证码
randomcode_refresh();
form 表单如下
<FORMid="loginform"name="loginform"action="${baseurl}loginsubmit.action"
method="post">