1.1 用户授权
给用户分配操作权限,用户认证通过后,操作指定权限的功能。
用户授权通过数据模型:
用户表、角色表、权限表(细化到操作链接)、用户角色关系表、角色权限关系表。
企业中在实现用户授权功能时,通常对上边通过数据模型进行修改。
本系统对权限表进行扩展:菜单表(模块表)、操作表(操作链接)
1.2 用户认证实现流程
本系统采用用户名密码认证方法。
第一步:用户访问系统
第二步:系统对用户访问资源校验,该用户是否通过认证
如果用户已经认证,放行,用户继续操作。
如果用户没有认证,如果访问的是公开资源地址(无需认证即可访问),系统就放行,用户继续操作
如果用户没有认证,如果访问的不是公开资源地址,拦截,跳转登陆页面
第三步:用户进入登陆页面
如果用户没有认证,如果访问的不是公开资源地址,拦截,跳转登陆页面
第四步:用户输入用户名、密码进行身份认证
如果认证通过进入系统首页
如果认证不通过进入登陆页面。
认证过程:根据用户账号和密码进行认证。
1.3 用户认证实现
用户登陆功能实现。
登陆页面上要有验证码:随机产生代码,将代码存入session。
validatecode.jsp(验证码jsp)
随机产生代码存入session:
1-验证码jsp
//将生成的验证码存入session
session.setAttribute("validateCode", capstr);
2-bean
/**
* 用户身份信息,存入session
* 由于tomcat将session会序列化在本地硬盘上,所以使用Serializable接口
* 重启tomcat session依然有效
*/
public class ActiveUser implements java.io.Serializable {
private String userid;//用户账号
private String username;//用户名称
private String groupid;//用户类型
private String groupname;//用户类型名称
private Menu menu;//操作菜单
private List<Operation> operationList;
//操作权限,包括用户点击菜单及操作菜单功能所有链接权限
3- service
接口功能:校验用户身份信息
接口参数:用户账号、用户密码
接口返回值:用户身份信息
@Override
public ActiveUser checkUserInfo(String userId, String pwd) throws Exception {
// 校验用户是否存在
Sysuser sysuser = this.findSysuserByUserId(userId);
if (sysuser == null) {
ResultUtil.throwExcepion(ResultUtil.createFail(Config.MESSAGE, 101, null));
}
String pwd_db = sysuser.getPwd();
String pwd_md5 = new MD5().getMD5ofStr(pwd);
if (!pwd_md5.equalsIgnoreCase(pwd_db)) {
// 用户名或密码错误
ResultUtil.throwExcepion(ResultUtil.createFail(Config.MESSAGE, 114, null));
}
ActiveUser activeUser = new ActiveUser();
activeUser.setUserid(userId);
activeUser.setUsername(sysuser.getUsername());
activeUser.setSysid(sysuser.getSysid());
activeUser.setGroupid(sysuser.getGroupid());
String sysmc = this.findSysidBySysid(sysuser.getSysid(), sysuser.getGroupid());
activeUser.setSysmc(sysmc);
return activeUser;
}
4 -action
/**
* 登录认证 2017-5-26
* @return
* @throws Exception
*/
@RequestMapping("login")
public String login() throws Exception{
return "/base/login";
}
/**
* 登录提交 2017-5-26
* 注意入参和jsp页面保持一致,今天这里出了错 userid 和userId
*/
@RequestMapping("loginsubmit")
public @ResponseBody SubmitResultInfo
loginsubmit(HttpSession session,String userid, String pwd, String validateCode)
throws Exception{
String validateCode_session = (String) session.getAttribute("validateCode");
if(validateCode_session != null && !validateCode_session.equals(validateCode)) {
//验证码输入错误
ResultUtil.throwExcepion(ResultUtil.createFail(Config.MESSAGE, 113,
null));
}
ActiveUser activeUser = userService.checkUserInfo(userid, pwd);
session.setAttribute(Config.ACTIVEUSER_KEY, activeUser);
return ResultUtil.createSubmitResult(ResultUtil.createSuccess(Config.MESSAGE, 107, new Object[]{""}));
}
/**
* 退出 2017-5-26
*/
@RequestMapping("logout")
public String logout(HttpSession session) throws Exception{
// session 过期
session.invalidate();
return "redirect:login.action";
}
5- 登录jsp
<FORM id="loginform" name="loginform" action="${baseurl}loginsubmit.action"
method="post">
<input type="button" onclick="loginsubmit()" value="登 录" />
//登录提示方法
function loginsubmit() {
//if(checkinput()){//校验表单,如果校验通过则执行jquerySubByFId
//ajax form提交
jquerySubByFId('loginform', login_commit_callback,null,'json');
//}
}
//登录提示回调方法
function login_commit_callback(data) {
message_alert(data);
var type = data.resultInfo.type;
if (1 == type) {//如果登录成功,这里1秒后执行跳转到首页
setTimeout("tofirst()", 1000);
} else {
//登录错误,重新刷新验证码
randomcode_refresh();
}
}
//刷新验证码
//实现思路,重新给图片的src赋值,后边加时间,防止缓存
function randomcode_refresh() {
$("#randomcode_img").attr('src',
'${baseurl}validatecode.jsp?time' + new Date().getTime());
}
验证码图片
<img id="randomcode_img" src="${baseurl}validatecode.jsp"/>
//回首页 防止出现页面嵌套
function tofirst(){
//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';
}
}
1.4 用户身份校验
通常使用filter过虑 器,本系统采用springmvc拦截器实现。
springmvc拦截器是基于处理器映射器HandlerMapping进行拦截。
可以采用一种方法定义一处拦截器,自动在每个HandlerMapping中进行注册。
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="yycg.base.filter.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器定义,需要实现HanlderInterceptor。
拦截器
public class LoginInterceptor implements HandlerInterceptor{
//执行时机:action方法执行完成,已经 返回modelAndView,执行。
//使用场景:统一处理系统异常,在这里统一记录系统日志 ,监控action方法执行时间
// ,在preHandle记录开始时间,在afterCompletion记录结束时间
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object obj, Exception handler)
throws Exception {
}
//执行时机:进入action方法,在返回modelAndView之前执行
//使用场景:在这里统一对返回数据进行处理,比如统一添加菜单 导航
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
}
//执行时机:进入action方法之前执行
//使用场景:用于用户认证、用户授权拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object obj) throws Exception {
//校验用户身份是否合法
HttpSession session = request.getSession();
ActiveUser activeUser = (ActiveUser) session.getAttribute(Config.ACTIVEUSER_KEY);
if (activeUser != null) {
// 用户已登录放行
return true;
}
//校验用户访问是否是公开资源 地址
List<String> open_urls = ResourcesUtil.gekeyList(Config.ANONYMOUS_ACTIONS);
String url = request.getRequestURI();
for(String open_url:open_urls){
if(url.indexOf(open_url) >= 0){
//如果访问的是公开 地址则放行
return true;
}
}
//拦截用户操作,跳转到登陆页面
request.getRequestDispatcher("/WEB-INF/jsp/base/login.jsp").forward(request, response);
return false;
}
}
修改--
//拦截用户操作,跳转到登陆页面
/*request.getRequestDispatcher("/WEB-INF/jsp/base/login.jsp").forward(request, response);*/
return false;
修改 -->
//抛出异常,异常代码106(需要登陆后继续操作)
ResultUtil.throwExcepion(ResultUtil.createWarning(Config.MESSAGE, 106, null));
异常处理器修改 -->
String view = "/base/error";
//异常代码
int messageCode = exceptionResultInfo.getResultInfo().getMessageCode();
//如果是106则跳转到登陆
if(messageCode==106){
//跳转到登陆
view = "/base/login";
}