RBAC
基于角色的权限访问控制(Role-Based Access Control)在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。
在IEDA中,打开DATABASE菜单,连接数据库
一共5张表,很好理解,
用户和角色的关系:一个用户可以拥有多个角色,相反一个角色也可以被多个用户所拥有
角色和权限的关系:一个角色可以拥有多个权限,相反一个权限也可以被多个角色所拥有
建库和表的sql我这里就不贴了,好了,前期的配置到此就结束了,接下来下面正式进入开发之旅。。。。。。。。。。
//实现用户的登录--拦截认证--密码加密后验证登录
login.jsp
<%-- Created by IntelliJ IDEA. User: shaojiang Date: 2019/1/20 Time: 下午7:07 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name="renderer" content="webkit|ie-comp|ie-stand"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" /> <meta http-equiv="Cache-Control" content="no-siteapp" /> <!--[if lt IE 9]> <script type="text/javascript" src="/statics/lib/html5shiv.js"></script> <script type="text/javascript" src="/statics/lib/respond.min.js"></script> <![endif]--> <link href="/statics/h-ui/css/H-ui.min.css" rel="stylesheet" type="text/css" /> <link href="/statics/h-ui.admin/css/H-ui.login.css" rel="stylesheet" type="text/css" /> <link href="/statics/h-ui.admin/css/style.css" rel="stylesheet" type="text/css" /> <link href="/statics/lib/Hui-iconfont/1.0.8/iconfont.css" rel="stylesheet" type="text/css" /> <!--[if IE 6]> <script type="text/javascript" src="/statics/lib/DD_belatedPNG_0.0.8a-min.js" ></script> <script>DD_belatedPNG.fix('*');</script> <![endif]--> <title>JavaEE权限管理系统</title> <meta name="keywords" content="H-ui.admin v3.1,H-ui网站后台模版,后台模版下载,后台管理系统模版,HTML后台模版下载"> <meta name="description" content="H-ui.admin v3.1,是一款由国人开发的轻量级扁平化网站后台模板,完全免费开源的网站后台管理系统模版,适合中小型CMS后台系统。"> </head> <body> <input type="hidden" id="TenantId" name="TenantId" value="" /> <div class="header">JavaEE权限管理系统</div> <div class="loginWraper"> <div id="loginform" class="loginBox"> <form id="login_form1" class="form form-horizontal" onsubmit="return false" action="##" method="post"> <div style="color: red;text-align: center;">${requestScope.loginError}</div> <div class="row cl"> <label class="form-label col-xs-3"><i class="Hui-iconfont"></i></label> <div class="formControls col-xs-8"> <input id="userName" name="userName" type="text" placeholder="账户" class="input-text size-L"> </div> </div> <div class="row cl"> <label class="form-label col-xs-3"><i class="Hui-iconfont"></i></label> <div class="formControls col-xs-8"> <input id="password" name="password" type="password" placeholder="密码" class="input-text size-L"> </div> </div> <%--<div class="row cl">--%> <%--<div class="formControls col-xs-8 col-xs-offset-3">--%> <%--<input class="input-text size-L" type="text" placeholder="验证码" onblur="if(this.value==''){this.value='验证码:'}" onclick="if(this.value=='验证码:'){this.value='';}" value="验证码:" style="width:150px;">--%> <%--<img src=""> <a id="kanbuq" href="javascript:;">看不清,换一张</a> </div>--%> <%--</div>--%> <div class="row cl"> <div class="formControls col-xs-8 col-xs-offset-3"> <label for="rememberMe"> <input type="checkbox" name="rememberMe" id="rememberMe" value=""> 使我保持登录状态</label> </div> </div> <div class="row cl"> <div class="formControls col-xs-8 col-xs-offset-3"> <input id="sub_login" name="" type="button" class="btn btn-success radius size-L" value=" 登 录 "> <%--<input name="" type="reset" class="btn btn-default radius size-L" value=" 取 消 ">--%> </div> </div> </form> </div> </div> <div class="footer">Copyright 通用权限管理系统 by H-ui.admin v3.1</div> <script type="text/javascript" src="/statics/lib/jquery/1.9.1/jquery.min.js"></script> <script type="text/javascript" src="/statics/h-ui/js/H-ui.min.js"></script> <script type="text/javascript" src="/statics/lib/layer/2.4/layer.js"></script> <script type="text/javascript"> //当登录超时,会跳转到登录页面,如果在框架中加载了登录页,首先进行判断,如果不是*路径,就导致*路径 if (window.top!=window.self) { //alert("执行了"); window.top.location.href = '/admin/login'; } $(function() { // 读取cookies中的用户信息 var rem = $.cookie('rememberMe'); if(rem){ $("#rememberMe").prop("checked",true); $("#userName").val($.cookie("username")); $("#password").val($.cookie("password")); } //登录 $("#sub_login").click(function () { var username = $("#userName").val(); var password = $("#password").val(); if(!username){ layer.msg("请输入用户名"); $("#userName").focus().select(); return false; }else if(!password){ layer.msg("请输入登录密码"); $("#password").focus().select(); return false; }else { //验证是否需要保存账户信息到cookies saveCookies(); //alert($('#login_form1').serialize()); //登录系统 $.ajax({ //几个参数需要注意一下 type: "POST",//方法类型 dataType: "json",//预期服务器返回的数据类型 url: "/admin/login" ,//url data: $('#login_form1').serialize(), success: function (data) { console.log(data.result);//打印服务端返回的数据(调试用) if (data.result == 'SUCCESS'||data.result == 200) { window.location.href = "/admin/main"; }else { layer.msg("登录失败:"+data.result.toString(),{icon:5,time:2000}); } }, error : function() { layer.msg(data.result.toString()); } }); } }); }); /** * jquery.cookie.js 是一个轻量级的cookie 插件,可以读取、写入、删除 cookie。 * H-ui.js 中已封装jquery.cookie.js,无需单独下载。 */ function saveCookies() { if($("#rememberMe").is(":checked")){ //alert("记住我"); var username = $("#userName").val(); var password = $("#password").val(); //创建一个cookie并设置有效时间为 7天: //如果没有指定有效期,所创建的cookie有效期默认到用户关闭浏览器为止 $.cookie("rememberMe","true",{expires:7}); $.cookie("username",username,{expires:7 }); $.cookie("password",password,{expires:7 }); }else{ $.cookie("rememberMe","false",{expires:-1}); $.cookie("username","",{ expires:-1 }); $.cookie("password","",{ expires:-1 }); } } </script> </body> </html>View Code
AdminController
/** * 管理员登录 * @return */ @RequestMapping(value = "/login",method = RequestMethod.POST) @ResponseBody public Map<String,Object> adminLogin( HttpServletRequest request, HttpSession session) { Map<String,Object> resultMap = new HashMap<String,Object>(); if(request.getParameter("userName")==null|| request.getParameter("password")==null){ resultMap.put("result","用户名或密码不能为空"); } //获取用户名和密码 String userName = request.getParameter("userName").toString(); String password = request.getParameter("password").toString(); //查询数据库该用户是否存在 AdminUser adminUser = adminUserService.findAdminUserByLoginName(userName); if(adminUser!=null){ //logger.info("adminUser:"+adminUser.toString()); //将用户的密码进行加密后返回,再进行比对 String encryptPassword = passwordEncryption.encryption(password, adminUser.getLoginName().toString()); if(adminUser.getLoginName().equals(userName)&& adminUser.getPassword().equals(encryptPassword)) { if(adminUser.getState()==1){ //验证通过,保存登录信息到session,转发到管理员后台控制器 session.setAttribute("adminUser",adminUser); resultMap.put("result","SUCCESS"); }else { resultMap.put("result","账户异常!请联系系统管理员!"); } }else { resultMap.put("result","用户名或密码错误!"); } }else { resultMap.put("result","用户名不存在!"); } return resultMap; }View Code
登录时用到了passwordEncryption服务类,该类负责进行密码的加密,使用自动注入引用
@Autowired
private PasswordEncryption passwordEncryption;
我是放在了service子模块中的,这样子方便扫描
PasswordEncryption类:
package com.supin51.service.impl; import org.apache.shiro.crypto.hash.SimpleHash; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.Serializable; /** * @Author:ShaoJiang * @description: apache shiro 的SimpleHash工具类加密 * @Date: created in 上午10:57 2019/1/26 * @Modified By: */ @Service public class PasswordEncryption{ /** * 基于注解的装配,这样可以在encrypt.properties属性文件中更改配置,在这里使用@Value进行注解装配获取到值
* 后期如果需要更改加密类型,可在属性文件中更改其他算法:md5,sha1,sha-128,sha-256,sha-512 * 使用@Value的类,在spring中,不能直接通过new 操作符来使用,这样获取不到值的 * 而是在需要使用的地方,通过spring的注解 @Autowired 来使用, * 例如:@Autowired private PasswordEncryption passwordEncryption; */ @Value("${algorithmName}") private String algorithmName;//加密算法,md5,sha1,sha-128,sha-256,sha-512 @Value("${hashIterations}") private int hashIterations;//散列次数 @Value("${isHex}") private boolean isHex;//是否使用十六进制编码,设置false后将启用Base64编码 /** * 密码加密 * @param password 加密前的密码 * @param salt 盐值(传递当前的用户名用作盐值) * @return */ public String encryption(String password, String salt) { String encryptStr = ""; if(isHex) { //使用十六进制进行编码 //带salt(盐值)和散列加密后,再用十六进制编码 encryptStr = new SimpleHash(algorithmName,password,salt,hashIterations).toHex(); //System.out.print("十六进制编码"); }else { //使用Base64进行编码 //带salt(盐值)和散列加密后,再用Base64编码 encryptStr = new SimpleHash(algorithmName,password,salt,hashIterations).toBase64(); //System.out.print("Base64编码"); } return encryptStr; } }
应为拦截了所有路径,所以还要添加认证拦截器:
AuthenticationInterceptor类:
package com.supin51.interceptor; import com.supin51.domain.AdminUser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @Author:ShaoJiang * @description:登录认证拦截 * @Date: created in 下午8:18 2019/1/21 * @Modified By: */ public class AuthenticationInterceptor implements HandlerInterceptor { private static final Log logger = LogFactory.getLog(AuthenticationInterceptor.class); //定义不需要拦截的URL路径 private static final String[] NO_INTERCEPTOR_URL = {"/admin/login","/404","/favicon.ico"}; /* * return true 才会继续执行下列两个方法(请求继续),否则整个请求结束 * 该方法主要进行拦截处理,该方法在Controller处理之前调用, * */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { boolean flag = false; //获取请求的路径进行判断 String servletUrl = request.getServletPath(); logger.info("url认证拦截器:preHandle-------->"+servletUrl); //循环拦截的URL路径,如果当前请求的URL中包含需要拦截的URL,返回true for (String s :NO_INTERCEPTOR_URL) { if(servletUrl.contains(s)){ flag = true; break; } } //拦截请求 if(!flag){ //获取session中的用户信息 AdminUser adminUser = (AdminUser)request.getSession().getAttribute("adminUser"); //如果用户已登录,放行,否则拦截 if(adminUser!=null){ logger.info("url认证拦截器:preHandle-------->用户已登录,放行请求-------->"); flag = true; }else { logger.info("url认证拦截器:preHandle-------->用户未登录,拦截请求-------->"); request.setAttribute("message","登录信息失效,请重新登录"); //只适合跳转页面,URL地址保持不变 //request.getRequestDispatcher("user1/login").forward(request,response); response.sendRedirect("/admin/login");//重定向到控制器,URL地址改变 } } return flag; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { logger.info("url认证拦截器:postHandle-------->"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.info("url认证拦截器:afterCompletion-------->"); } }
至此,整个登录的实现流程结束。本小节结束,下一小节将实现,登录成功后的权限菜单显示,基于自定义注解方法级别的权限菜单的拦截验证。