2017年9月3日 实现网站的权限管理
现在各个企业管理网站对登录的账号都要进行权限管理,并且相当重要,每个账号登录进去所能看到的东西大不相同,下面是实现该功能的一个的一种方法。
需求:
权限:权限是使用者操作系统中功能模块的能力,如“角色管理”模块、“资费管 理”模块和“账单管理”模块等。通过指定权限,可将使用者的操作限定在指定的 范围内,以保证操作的安全。
例如,一个使用者拥有“资费管理”权限,表示该使 用者可以操作“资费管理”模块,以执行资费管理的操作。权限由 NetCTOSS 系 统内置,使用者不可以进行修改。
使用者对本系统的各功能模块的访问都是受权限 控制的,因此,权限决定了使用者可以执行的操作。
角色:角色是多种权限的集合,可通过授予使用者某种角色,以简化权限的管理。 比如,角色“账号管理员”同时具有“帐务账号”模块和“业务账号”模块的权限。
如果设置某使用者的角色为“账号管理员”,则意味着该使用者可以同时操作“帐 务账号“和”业务账号“模块。
准备工作:
Step1、将权限等级权限角色等信息录入数据库:
1 --模块表 2 create table module_info( 3 module_id number(4) constraint module_info_id_pk primary key, 4 name varchar2(50) not null 5 ); 6 7 create sequence module_seq start with 100; 8 9 --角色表 10 create table role_info( 11 role_id number(4) constraint role_info_id_pk primary key, 12 name varchar2(50) not null 13 ); 14 15 create sequence role_seq start with 1000; 16 17 --角色模块表 18 create table role_module( 19 role_id number(4) not null, 20 module_id number(4) not null, 21 constraint role_module_pk primary key(role_id,module_id) 22 ); 23 24 25 26 --管理员表 27 create table admin_info( 28 admin_id number(8) primary key not null, 29 admin_code varchar2(30) not null, 30 password varchar2(30) not null, 31 name varchar2(30) not null, 32 telephone varchar2(15), 33 email varchar2(50), 34 enrolldate date default sysdate not null 35 ); 36 37 create sequence admin_seq start with 10000; 38 39 40 --管理员角色表 41 create table admin_role( 42 admin_id number(8) not null, 43 role_id number(4) not null, 44 constraint admin_role_pk primary key(admin_id,role_id) 45 ); 46 47 48 49 --模块表 50 insert into MODULE_INFO values(1,'角色管理'); 51 insert into MODULE_INFO values(2,'管理员'); 52 insert into MODULE_INFO values(3,'资费管理'); 53 insert into MODULE_INFO values(4,'账务账号'); 54 insert into MODULE_INFO values(5,'业务账号'); 55 insert into MODULE_INFO values(6,'账单管理'); 56 insert into MODULE_INFO values(7,'报表'); 57 commit; 58 --角色表 59 insert into role_info values(100,'管理员'); 60 insert into role_info values(200,'营业员'); 61 insert into role_info values(300,'经理'); 62 insert into role_info values(400,'aaa'); 63 insert into role_info values(500,'bbb'); 64 insert into role_info values(600,'ccc'); 65 commit; 66 --角色模块表 67 insert into role_module values(100,1); 68 insert into role_module values(100,2); 69 insert into role_module values(200,3); 70 insert into role_module values(200,4); 71 insert into role_module values(200,5); 72 insert into role_module values(200,6); 73 insert into role_module values(300,7); 74 commit; 75 --管理员表 76 insert into admin_info values(2000,'admin','123','ADMIN','123456789','admin@tarena.com.cn',sysdate); 77 insert into admin_info values(3000,'zhangfei','123','ZhangFei','123456789','zhangfei@tarena.com.cn',sysdate); 78 insert into admin_info values(4000,'liubei','123','LiuBei','123456789','liubei@tarena.com.cn',sysdate); 79 insert into admin_info values(5000,'caocao','123','CaoCao','123456789','caocao@tarena.com.cn',sysdate); 80 insert into admin_info values(6000,'aaa','123','AAA','123456789','aaa@tarena.com.cn',sysdate); 81 insert into admin_info values(7000,'bbb','123','BBB','123456789','bbb@tarena.com.cn',sysdate); 82 commit; 83 --管理员角色表 84 insert into admin_role values(2000,100); 85 insert into admin_role values(3000,200); 86 insert into admin_role values(4000,300); 87 insert into admin_role values(5000,100); 88 insert into admin_role values(5000,200); 89 insert into admin_role values(5000,300);
Step2、连接数据库:
1 #db connection parameters 2 driver=oracle.jdbc.driver.OracleDriver 3 url=jdbc:oracle:thin:@176.217.20.254:1521:tarena 4 user=gg2014 5 password=gg2014 6 #datasource parameters 7 initsize=1 8 maxsize=3
1 <util:properties id="jdbc" location="classpath:jdbc.properties"/> 2 3 <!-- 定义数据源 --> 4 <bean id="ds" 5 class="org.apache.commons.dbcp.BasicDataSource" 6 destroy-method="close"> 7 <property name="url" value="#{jdbc.url}"/> 8 <property name="driverClassName" value="#{jdbc.driver}"/> 9 <property name="username" value="#{jdbc.user}"/> 10 <property name="password" value="#{jdbc.password}"/> 11 </bean>
Step3、其他xml文件中的设置(包含拦截器等):
1 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 2 <property name="dataSource" ref="ds" /> 3 <property name="mapperLocations" value="classpath:com/tarena/entity/*.xml"/> 4 </bean> 5 6 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 7 <property name="basePackage" value="com.tarena.dao" /> 8 <property name="annotationClass" 9 value="com.tarena.annotation.MyBatisRepository"/> 10 </bean> 11 12 <context:component-scan base-package="com.tarena" /> 13 14 <!-- 支持MVC注解 --> 15 <mvc:annotation-driven /> 16 17 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 18 <property name="prefix" value="/WEB-INF/"/> 19 <property name="suffix" value=".jsp"/> 20 </bean> 21 22 <!-- 注册拦截器 --> 23 <mvc:interceptors> 24 <!-- 登录检查拦截器 --> 25 <mvc:interceptor> 26 <mvc:mapping path="/**"/> 27 <mvc:exclude-mapping path="/login/toLogin.do"/> 28 <mvc:exclude-mapping path="/login/login.do"/> 29 <mvc:exclude-mapping path="/login/createImage.do"/> 30 <bean class="com.tarena.interceptor.LoginInterceptor"/> 31 </mvc:interceptor> 32 <!-- 判断当前模块拦截器 --> 33 <mvc:interceptor> 34 <mvc:mapping path="/**"/> 35 <bean class="com.tarena.interceptor.CurrentModuleInterceptor"/> 36 </mvc:interceptor> 37 <!-- 权限检查拦截器 --> 38 <mvc:interceptor> 39 <mvc:mapping path="/**"/> 40 <mvc:exclude-mapping path="/login/*"/> 41 <bean class="com.tarena.interceptor.CheckModuleInterceptor"/> 42 </mvc:interceptor> 43 </mvc:interceptors> 44 45 <!-- 开启AOP注解扫描 --> 46 <aop:aspectj-autoproxy proxy-target-class="true"/> 47 48 <!-- 处理异常 --> 49 <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> 50 <property name="exceptionMappings"> 51 <props> 52 <prop key="java.lang.Exception">main/error</prop> 53 </props> 54 </property> 55 </bean> 56 57 <!-- 声明式事务 --> 58 <bean id="txManager" 59 class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 60 <property name="dataSource" ref="ds" /> 61 </bean> 62 <tx:advice id="txAdvice" transaction-manager="txManager"> 63 <tx:attributes> 64 <tx:method name="find*" read-only="true" /> 65 <tx:method name="to*" read-only="true" /> 66 <tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception"/> 67 <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/> 68 <tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/> 69 </tx:attributes> 70 </tx:advice> 71 <aop:config proxy-target-class="true"> 72 <aop:advisor advice-ref="txAdvice" pointcut="within(com.tarena.controller..*)" /> 73 </aop:config>
Step4、写实体类,一个登录的账号信息,一个是权限的名称及对应编号
1 package com.tarena.entity; 2 3 import java.sql.Timestamp; 4 import java.util.List; 5 6 public class Admin { 7 8 private Integer admin_id; 9 private String admin_code; 10 private String password; 11 private String name; 12 private String telephone; 13 private String email; 14 private Timestamp enrolldate; 15 16 private List<Role> roles; 17 private List<Integer> roleIds; 18 19 public Integer getAdmin_id() { 20 return admin_id; 21 } 22 23 public void setAdmin_id(Integer admin_id) { 24 this.admin_id = admin_id; 25 } 26 27 public List<Role> getRoles() { 28 return roles; 29 } 30 31 public void setRoles(List<Role> roles) { 32 this.roles = roles; 33 } 34 35 public List<Integer> getRoleIds() { 36 return roleIds; 37 } 38 39 public void setRoleIds(List<Integer> roleIds) { 40 this.roleIds = roleIds; 41 } 42 43 public String getAdmin_code() { 44 return admin_code; 45 } 46 47 public void setAdmin_code(String admin_code) { 48 this.admin_code = admin_code; 49 } 50 51 public String getPassword() { 52 return password; 53 } 54 55 public void setPassword(String password) { 56 this.password = password; 57 } 58 59 public String getName() { 60 return name; 61 } 62 63 public void setName(String name) { 64 this.name = name; 65 } 66 67 public String getTelephone() { 68 return telephone; 69 } 70 71 public void setTelephone(String telephone) { 72 this.telephone = telephone; 73 } 74 75 public String getEmail() { 76 return email; 77 } 78 79 public void setEmail(String email) { 80 this.email = email; 81 } 82 83 public Timestamp getEnrolldate() { 84 return enrolldate; 85 } 86 87 public void setEnrolldate(Timestamp enrolldate) { 88 this.enrolldate = enrolldate; 89 } 90 91 }
package com.tarena.entity; public class Module { private Integer module_id; private String name; public Integer getModule_id() { return module_id; } public void setModule_id(Integer module_id) { this.module_id = module_id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Step5、编写DAO的接口
package com.tarena.dao; import java.util.List; import java.util.Map; import com.tarena.annotation.MyBatisRepository; import com.tarena.entity.Admin; import com.tarena.entity.Module; import com.tarena.entity.page.Page; @MyBatisRepository public interface AdminDao { List<Module> findModulesByAdmin(int adminId); }
Step6、编写实现该接口的SQL语句
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" 3 "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> 4 5 <mapper namespace="com.tarena.dao.AdminDao"> 6 7 8 <select id="findModulesByAdmin" 9 parameterType="int" 10 resultType="com.tarena.entity.Module"> 11 select * from module_info where module_id in ( 12 select rm.module_id 13 from admin_role ar 14 inner join role_info ri on ri.role_id=ar.role_id 15 inner join role_module rm on rm.role_id=ri.role_id 16 where ar.admin_id=#{adminId} 17 ) order by module_id 18 </select> 19 20 </mapper>
Step6.5、验证码生成的方法
1 package com.tarena.util; 2 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.awt.Graphics; 6 import java.awt.image.BufferedImage; 7 import java.io.ByteArrayInputStream; 8 import java.io.ByteArrayOutputStream; 9 import java.io.IOException; 10 import java.io.InputStream; 11 import java.util.HashMap; 12 import java.util.Map; 13 import java.util.Random; 14 15 import com.sun.image.codec.jpeg.JPEGCodec; 16 import com.sun.image.codec.jpeg.JPEGImageEncoder; 17 18 public final class ImageUtil { 19 20 private static final char[] chars = { '0', '1', '2', '3', '4', '5', '6', 21 '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I' }; 22 private static final int SIZE = 4; 23 private static final int LINES = 5; 24 private static final int WIDTH = 80; 25 private static final int HEIGHT = 40; 26 private static final int FONT_SIZE = 30; 27 28 public static Map<String, BufferedImage> createImage() { 29 StringBuffer sb = new StringBuffer(); 30 BufferedImage image = new BufferedImage(WIDTH, HEIGHT, 31 BufferedImage.TYPE_INT_RGB); 32 Graphics graphic = image.getGraphics(); 33 graphic.setColor(Color.LIGHT_GRAY); 34 graphic.fillRect(0, 0, WIDTH, HEIGHT); 35 Random ran = new Random(); 36 // 画随机字符 37 for (int i = 1; i <= SIZE; i++) { 38 int r = ran.nextInt(chars.length); 39 graphic.setColor(getRandomColor()); 40 graphic.setFont(new Font(null, Font.BOLD + Font.ITALIC, FONT_SIZE)); 41 graphic.drawString(chars[r] + "", (i - 1) * WIDTH / SIZE, 42 HEIGHT / 2); 43 sb.append(chars[r]);// 将字符保存,存入Session 44 } 45 // 画干扰线 46 for (int i = 1; i <= LINES; i++) { 47 graphic.setColor(getRandomColor()); 48 graphic.drawLine(ran.nextInt(WIDTH), ran.nextInt(HEIGHT), 49 ran.nextInt(WIDTH), ran.nextInt(HEIGHT)); 50 } 51 Map<String, BufferedImage> map = new HashMap<String, BufferedImage>(); 52 map.put(sb.toString(), image); 53 return map; 54 } 55 56 public static Color getRandomColor() { 57 Random ran = new Random(); 58 Color color = new Color(ran.nextInt(256), ran.nextInt(256), 59 ran.nextInt(256)); 60 return color; 61 } 62 63 public static InputStream getInputStream(BufferedImage image) 64 throws IOException { 65 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 66 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos); 67 encoder.encode(image); 68 byte[] imageBts = bos.toByteArray(); 69 InputStream in = new ByteArrayInputStream(imageBts); 70 return in; 71 } 72 73 }
Step7、在控制层编写用户登入的逻辑
1 package com.tarena.controller; 2 3 import java.awt.image.BufferedImage; 4 import java.io.OutputStream; 5 import java.util.HashMap; 6 import java.util.List; 7 import java.util.Map; 8 import javax.annotation.Resource; 9 import javax.imageio.ImageIO; 10 import javax.servlet.http.HttpServletResponse; 11 import javax.servlet.http.HttpSession; 12 import org.springframework.stereotype.Controller; 13 import org.springframework.web.bind.annotation.RequestMapping; 14 import org.springframework.web.bind.annotation.ResponseBody; 15 import com.tarena.dao.AdminDao; 16 import com.tarena.entity.Admin; 17 import com.tarena.entity.Module; 18 import com.tarena.util.ImageUtil; 19 20 @Controller 21 @RequestMapping("/login") 22 public class LoginController extends BaseController { 23 24 /* 25 * 设置四种状态,对应不同的错误 26 */ 27 private final static int SUCCESS = 0; 28 29 private final static int ADMIN_CODE_ERROR = 1; 30 31 private final static int PASSWORD_ERROR = 2; 32 33 private final static int IMAGE_CODE_ERROR = 3; 34 35 @Resource 36 private AdminDao adminDao; 37 38 @RequestMapping("/toLogin.do") 39 public String toLogin() { 40 return "main/login"; 41 } 42 43 @RequestMapping("/toIndex.do") 44 public String toIndex() { 45 return "main/index"; 46 } 47 48 @RequestMapping("/nopower.do") 49 public String nopower() { 50 return "main/nopower"; 51 } 52 53 @RequestMapping("/login.do") 54 @ResponseBody 55 public Map<String, Object> login( 56 String adminCode, 57 String password, 58 String code, 59 HttpSession session) { 60 Map<String, Object> result = new HashMap<String, Object>(); 61 62 String imageCode = (String) session.getAttribute("imageCode"); 63 if(code == null 64 || !code.equalsIgnoreCase(imageCode)) { 65 result.put("flag", IMAGE_CODE_ERROR); 66 return result; 67 } 68 69 Admin admin = adminDao.findByCode(adminCode); 70 if(admin == null) { 71 result.put("flag", ADMIN_CODE_ERROR); 72 return result; 73 } else if (!admin.getPassword().equals(password)) { 74 result.put("flag", PASSWORD_ERROR); 75 return result; 76 } else { 77 //发送登录成功的admin号到session 78 session.setAttribute("admin", admin); 79 //获得登录这个admin号的权限范围 80 List<Module> modules = 81 adminDao.findModulesByAdmin(admin.getAdmin_id()); 82 session.setAttribute("allModules", modules); 83 result.put("flag", SUCCESS); 84 return result; 85 } 86 } 87 88 //验证码生成 89 @RequestMapping("/createImage.do") 90 public void createImage( 91 HttpServletResponse response, HttpSession session) 92 throws Exception { 93 Map<String, BufferedImage> imageMap = ImageUtil.createImage(); 94 String code = imageMap.keySet().iterator().next(); 95 session.setAttribute("imageCode", code); 96 97 BufferedImage image = imageMap.get(code); 98 99 response.setContentType("image/jpeg"); 100 OutputStream ops = response.getOutputStream(); 101 ImageIO.write(image, "jpeg", ops); 102 ops.close(); 103 } 104 105 }
Step8、用户在登录页面和登录后进入的主页及提示用户没有权限的页面
login.jsp:↓
1 <%@page pageEncoding="utf-8"%> 2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3 <html xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6 <title>达内-NetCTOSS</title> 7 <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" /> 8 <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" /> 9 <script type="text/javascript" language="javascript" src="../js/jquery-1.11.1.js"></script> 10 <script type="text/javascript" language="javascript"> 11 //登录校验 12 function check_login() { 13 var admin_code = $("#admin_code").val(); 14 if(admin_code == "") { 15 $("#admin_code_msg").text("请输入账号."); 16 return; 17 } 18 19 var password = $("#password").val(); 20 if(password == "") { 21 $("#password_msg").text("请输入密码."); 22 return; 23 } 24 25 var code = $("#code").val(); 26 if(code == "") { 27 $("#code_msg").text("请输入验证码."); 28 return; 29 } 30 31 $.post( 32 "login.do", 33 $("#myform").serialize(), 34 function(data) { 35 if(data.flag==1) { 36 //账号错误 37 $("#admin_code_msg").text("账号错误."); 38 } else if(data.flag==2) { 39 //密码错误 40 $("#password_msg").text("密码错误."); 41 } else if(data.flag==3) { 42 //验证码错误 43 $("#code_msg").text("验证码错误."); 44 change(); 45 } else { 46 //成功 47 location.href = "toIndex.do"; 48 } 49 } 50 ); 51 } 52 //设置提示信息 53 function set_msg(id, msg) { 54 $("#"+id).text(msg); 55 } 56 //刷新验证码 57 function change() { 58 $("#code_image").attr("src", "createImage.do?date=" + new Date().getTime()); 59 } 60 </script> 61 </head> 62 <body class="index"> 63 <div class="login_box"> 64 <form action="login.do" method="post" id="myform"> 65 <table> 66 <tr> 67 <td class="login_info">账号:</td> 68 <td colspan="2"> 69 <input type="text" name="adminCode" id="admin_code" class="width150" onfocus="set_msg('admin_code_msg','30长度的字母、数字和下划线');"/> 70 </td> 71 <td class="login_error_info"><span class="required" id="admin_code_msg">30长度的字母、数字和下划线</span></td> 72 </tr> 73 <tr> 74 <td class="login_info">密码:</td> 75 <td colspan="2"> 76 <input type="password" name="password" id="password" class="width150" onfocus="set_msg('password_msg','30长度的字母、数字和下划线');"/> 77 </td> 78 <td><span class="required" id="password_msg">30长度的字母、数字和下划线</span></td> 79 </tr> 80 <tr> 81 <td class="login_info">验证码:</td> 82 <td class="width70"><input name="code" type="text" class="width70" id="code" onfocus="set_msg('code_msg','');"/></td> 83 <td><img src="createImage.do" alt="验证码" title="点击更换" id="code_image" onclick="change();"/></td> 84 <td><span class="required" id="code_msg"></span></td> 85 </tr> 86 <tr> 87 <td></td> 88 <td class="login_button" colspan="2"> 89 <a href="javascript:check_login();"><img src="../images/login_btn.png" /></a> 90 </td> 91 <td><span class="required"></span></td> 92 </tr> 93 </table> 94 </form> 95 </div> 96 </body> 97 </html>
menu.jsp ↓
1 <%@page pageEncoding="utf-8"%> 2 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 3 <ul id="menu"> 4 <c:choose> 5 <c:when test="${currentModule==0 }"> 6 <li><a href="${pageContext.request.contextPath }/login/toIndex.do" class="index_on"></a></li> 7 </c:when> 8 <c:otherwise> 9 <li><a href="${pageContext.request.contextPath }/login/toIndex.do" class="index_off"></a></li> 10 </c:otherwise> 11 </c:choose> 12 13 <c:forEach items="${allModules }" var="module"> 14 <c:if test="${module.module_id==1 }"> 15 <c:choose> 16 <c:when test="${currentModule==1 }"> 17 <li><a href="${pageContext.request.contextPath }/role/findRole.do?currentPage=1" class="role_on"></a></li> 18 </c:when> 19 <c:otherwise> 20 <li><a href="${pageContext.request.contextPath }/role/findRole.do?currentPage=1" class="role_off"></a></li> 21 </c:otherwise> 22 </c:choose> 23 </c:if> 24 <c:if test="${module.module_id==2 }"> 25 <c:choose> 26 <c:when test="${currentModule==2 }"> 27 <li><a href="${pageContext.request.contextPath }/admin/findAdmin.do?currentPage=1" class="admin_on"></a></li> 28 </c:when> 29 <c:otherwise> 30 <li><a href="${pageContext.request.contextPath }/admin/findAdmin.do?currentPage=1" class="admin_off"></a></li> 31 </c:otherwise> 32 </c:choose> 33 </c:if> 34 <c:if test="${module.module_id==3 }"> 35 <c:choose> 36 <c:when test="${currentModule==3 }"> 37 <li><a href="${pageContext.request.contextPath }/cost/findCost.do?currentPage=1" class="fee_on"></a></li> 38 </c:when> 39 <c:otherwise> 40 <li><a href="${pageContext.request.contextPath }/cost/findCost.do?currentPage=1" class="fee_off"></a></li> 41 </c:otherwise> 42 </c:choose> 43 </c:if> 44 <c:if test="${module.module_id==4 }"> 45 <c:choose> 46 <c:when test="${currentModule==4 }"> 47 <li><a href="${pageContext.request.contextPath }/account/findAccount.do?currentPage=1" class="account_on"></a></li> 48 </c:when> 49 <c:otherwise> 50 <li><a href="${pageContext.request.contextPath }/account/findAccount.do?currentPage=1" class="account_off"></a></li> 51 </c:otherwise> 52 </c:choose> 53 </c:if> 54 <c:if test="${module.module_id==5 }"> 55 <c:choose> 56 <c:when test="${currentModule==5 }"> 57 <li><a href="${pageContext.request.contextPath }/service/findService.do?currentPage=1" class="service_on"></a></li> 58 </c:when> 59 <c:otherwise> 60 <li><a href="${pageContext.request.contextPath }/service/findService.do?currentPage=1" class="service_off"></a></li> 61 </c:otherwise> 62 </c:choose> 63 </c:if> 64 </c:forEach> 65 <li><a href="user/user_info.html" class="information_off"></a></li> 66 <li><a href="user/user_modi_pwd.html" class="password_off"></a></li> 67 </ul>
nopower.jsp
<%@page pageEncoding="utf-8"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>达内-NetCTOSS</title> <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" /> <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" /> <script language="javascript" type="text/javascript"> var timer; //启动跳转的定时器 function startTimes() { timer = window.setInterval(showSecondes,1000); } var i = 5; function showSecondes() { if (i > 0) { i--; document.getElementById("secondes").innerHTML = i; } else { window.clearInterval(timer); location.href = "<%=path%>/login/toIndex.do"; } } //取消跳转 function resetTimer() { if (timer != null && timer != undefined) { window.clearInterval(timer); //location.href = "index.html"; window.history.back(); } } </script> </head> <body class="error_power_page" onload="startTimes();"> <h1 id="error"> 您无权访问此页面, <span id="secondes">5</span> 秒后将自动跳转,立即跳转请点击 <a class="index.html" href="javascript:resetTimer();">返回</a> </h1> </body> </html>
Step9、写3个拦截器
CheckModuleInterceptor:↓
1 package com.tarena.interceptor; 2 3 import java.util.List; 4 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 8 import org.springframework.web.servlet.HandlerInterceptor; 9 import org.springframework.web.servlet.ModelAndView; 10 11 import com.tarena.entity.Module; 12 13 public class CheckModuleInterceptor implements HandlerInterceptor { 14 15 @Override 16 public void afterCompletion(HttpServletRequest arg0, 17 HttpServletResponse arg1, Object arg2, Exception arg3) 18 throws Exception { 19 20 } 21 22 @Override 23 public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, 24 Object arg2, ModelAndView arg3) throws Exception { 25 26 } 27 28 @SuppressWarnings("unchecked") 29 @Override 30 public boolean preHandle(HttpServletRequest request, 31 HttpServletResponse response, Object obj) throws Exception { 32 //获取登录用户有权限的所有模块 33 List<Module> modules = (List<Module>) 34 request.getSession().getAttribute("allModules"); 35 //获取用户当前要访问的模块 36 int currentModule = (Integer) 37 request.getSession().getAttribute("currentModule"); 38 //判断用户有权限的模块是否包含当前模块 39 for (Module module : modules) { 40 if (module.getModule_id() == currentModule) { 41 //有当前访问模块的权限 42 return true; 43 } 44 } 45 //没有当前访问模块的权限 46 response.sendRedirect( 47 request.getContextPath() + "/login/nopower.do"); 48 return false; 49 } 50 51 }
CurrentModuleInterceptor:↓
1 package com.tarena.interceptor; 2 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.http.HttpServletResponse; 5 import org.springframework.web.servlet.HandlerInterceptor; 6 import org.springframework.web.servlet.ModelAndView; 7 8 public class CurrentModuleInterceptor implements HandlerInterceptor { 9 10 @Override 11 public void afterCompletion(HttpServletRequest arg0, 12 HttpServletResponse arg1, Object arg2, Exception arg3) 13 throws Exception { 14 15 } 16 17 @Override 18 public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, 19 Object arg2, ModelAndView arg3) throws Exception { 20 21 } 22 23 @Override 24 public boolean preHandle(HttpServletRequest request, 25 HttpServletResponse response, Object obj) throws Exception { 26 // 判断当前用户访问的模块 27 String url = request.getRequestURL().toString(); 28 int currentModule = 0; // 默认0是NETCTOSS首页 29 if (url.contains("role")) { 30 currentModule = 1; 31 } else if (url.contains("admin")) { 32 currentModule = 2; 33 } else if (url.contains("cost")) { 34 currentModule = 3; 35 } else if (url.contains("account")) { 36 currentModule = 4; 37 } else if (url.contains("service")) { 38 currentModule = 5; 39 } 40 41 request.getSession().setAttribute( 42 "currentModule", currentModule); 43 44 return true; 45 } 46 47 }
LoginInterceptor:↓
1 package com.tarena.interceptor; 2 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.http.HttpServletResponse; 5 6 import org.springframework.web.servlet.HandlerInterceptor; 7 import org.springframework.web.servlet.ModelAndView; 8 9 import com.tarena.entity.Admin; 10 11 public class LoginInterceptor implements HandlerInterceptor { 12 13 @Override 14 public void afterCompletion(HttpServletRequest arg0, 15 HttpServletResponse arg1, Object arg2, Exception arg3) 16 throws Exception { 17 18 } 19 20 @Override 21 public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, 22 Object arg2, ModelAndView arg3) throws Exception { 23 24 } 25 26 @Override 27 public boolean preHandle(HttpServletRequest request, 28 HttpServletResponse response, Object obj) throws Exception { 29 Admin admin = (Admin) request.getSession().getAttribute("admin"); 30 if(admin == null) { 31 response.sendRedirect( 32 request.getContextPath() + "/login/toLogin.do"); 33 return false; 34 } else { 35 return true; 36 } 37 } 38 39 }
业务实现逻辑:
step1 用户登录
首先当用户访问toLogin.do时,
@RequestMapping("/toLogin.do") public String toLogin() { return "main/login"; }
这时用户在login.jsp生成的页面中填写账号密码和验证码,填写完毕后提交。
<form action="login.do" method="post" id="myform">
这时将跳转至login.do页面,就会运行控制器LoginController里的login()方法
@RequestMapping("/login.do") @ResponseBody public Map<String, Object> login( String adminCode, String password, String code, HttpSession session) { Map<String, Object> result = new HashMap<String, Object>(); String imageCode = (String) session.getAttribute("imageCode"); if(code == null || !code.equalsIgnoreCase(imageCode)) { result.put("flag", IMAGE_CODE_ERROR); return result; } Admin admin = adminDao.findByCode(adminCode); if(admin == null) { result.put("flag", ADMIN_CODE_ERROR); return result; } else if (!admin.getPassword().equals(password)) { result.put("flag", PASSWORD_ERROR); return result; } else { //发送登录成功的admin号到session session.setAttribute("admin", admin); //获得登录这个admin号的权限范围 List<Module> modules = adminDao.findModulesByAdmin(admin.getAdmin_id()); session.setAttribute("allModules", modules); result.put("flag", SUCCESS); return result; } }
如果账号和密码验证码有错误,将根据不同的错误生成不同的result结果,将在网页上显示。
在3个数据填写正确之后,页面跳转至toIndex.do,并且发送2个对象"admin"(用户名称)和" modules "(用户的权限编号)保存到session,
这里的modules是通过用admin的值调用findModulesByAdmin()方法获得的。
step2--modules的权限编号的获得
AdminDao接口里的 List<Module> findModulesByAdmin(int adminId) 方法;
实现在 AdminMapper.xml的映射里的SQL语句
<select id="findModulesByAdmin" parameterType="int" resultType="com.tarena.entity.Module"> select * from module_info(模块表) where module_id in ( select rm.module_id from admin_role ar inner join role_info(角色表) ri on ri.role_id=ar.role_id inner join role_module(角色模块表) rm on rm.role_id=ri.role_id where ar.admin_id=#{adminId} ) order by module_id </select>
这里是个链表,role_info ri关联ri.role_id,通过ar.role_id
role_module rm 关联 rm.role_id,通过ri.role_id
1、 登录的id是 admin_info管理员表,根据登录的admin_id获得admin_role表中的role_id,
再通过role_module中的role_id找到 role_module的module_id,再根据module_id获得后面的字符串,即可以直到登录的这个号有哪些权限
相当于,先获取是什么角色,再从是什么角色获取有什么权限
2、其数据库管理的逻辑是,每个账号使用者,可以用不同的角色(类似职位),而每个不同角色有不同的权限,从上而下则是首先可以增删改查角色,
然后再对每个角色所拥有的权限进行增删改查。
这里已经获取了登录账号所拥有的权限,回过头看login方法,在运行SQL语句之后将查询到的权限的所对应的int值全部放入到modules集合中。
List<Module> modules =
adminDao.findModulesByAdmin(admin.getAdmin_id());
step3 拦截器
在applicationContext.xml中配置3个拦截器,第1个LoginInterceptor在除了toLogin.do,Login.do,createImage.do(验证码)这3个页面不拦截外,
对所有页面进行拦截。第2个和第3个拦截器CurrentModuleInterceptor和CheckModuleInterceptor对所有页面进行拦截,断绝一切可能从其他地址
访问到所不拥有的权限能看到的模块。
<!-- 注册拦截器 --> <mvc:interceptors> <!-- 登录检查拦截器 --> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/login/toLogin.do"/> <mvc:exclude-mapping path="/login/login.do"/> <mvc:exclude-mapping path="/login/createImage.do"/> <bean class="com.tarena.interceptor.LoginInterceptor"/> </mvc:interceptor> <!-- 判断当前模块拦截器 --> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.tarena.interceptor.CurrentModuleInterceptor"/> </mvc:interceptor> <!-- 权限检查拦截器 --> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/login/*"/> <bean class="com.tarena.interceptor.CheckModuleInterceptor"/> </mvc:interceptor> </mvc:interceptors>
CurrentModuleInterceptor:
首先在CurrentModuleInterceptor拦截器中,将用户访问的链接转换为字符串,如果有包含role,admin,cost,account,service字符串,则按照其功能转换为对应的int值,并且返还给curentModule对象,命名为"currentModule"
并发送出去。
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception { // 判断当前用户访问的模块 String url = request.getRequestURL().toString(); int currentModule = 0; // 默认0是NETCTOSS首页 if (url.contains("role")) { currentModule = 1; } else if (url.contains("admin")) { currentModule = 2; } else if (url.contains("cost")) { currentModule = 3; } else if (url.contains("account")) { currentModule = 4; } else if (url.contains("service")) { currentModule = 5; } request.getSession().setAttribute( "currentModule", currentModule); return true; }
CheckModuleInterceptor
首先获取之前传入的allModules,即用户所拥有的权限对象,然后再获取用户之前访问链接而产生的对应的curentModule对象,强转为int型,因为权限编号为int,再通过foreach循环判断两者是否相等,即可以判断用户是否有权限进行访问。如果有权限则返回true,没有权限则跳转至"/login/nopower.do",即提示用户没有权限的页面,并且返回false
@SuppressWarnings("unchecked") @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception { //获取登录用户有权限的所有模块 List<Module> modules = (List<Module>) request.getSession().getAttribute("allModules"); //获取用户当前要访问的模块 int currentModule = (Integer) request.getSession().getAttribute("currentModule"); //判断用户有权限的模块是否包含当前模块 for (Module module : modules) { if (module.getModule_id() == currentModule) { //有当前访问模块的权限 return true; } } //没有当前访问模块的权限 response.sendRedirect( request.getContextPath() + "/login/nopower.do"); return false; }
step4
用户填写完账号密码验证码之后跳转至toIndex.do之后,程序访问index页面,
@RequestMapping("/toIndex.do") public String toIndex() { return "main/index"; }
而index页面导入了menu.jsp页面,接着程序走menu.jsp
<jsp:include page="/WEB-INF/main/menu.jsp" />
在menu.jsp中,使用循环查找之前传入的module对象中的值,有哪个数值就显示数值对应的页面,这样就做到了,只显示用户所拥有权限的对应页面(有多个就显示多个),没有的就不会显示出来。
<c:forEach items="${allModules }" var="module"> <c:if test="${module.module_id==1 }"> <c:choose> <c:when test="${currentModule==1 }"> <li><a href="${pageContext.request.contextPath }/role/findRole.do?currentPage=1" class="role_on"></a></li> </c:when> <c:otherwise> <li><a href="${pageContext.request.contextPath }/role/findRole.do?currentPage=1" class="role_off"></a></li> </c:otherwise> </c:choose> </c:if>
在数据库中录入的每个模块对应的int值
insert into MODULE_INFO values(1,'角色管理');
insert into MODULE_INFO values(2,'管理员');
insert into MODULE_INFO values(3,'资费管理');
insert into MODULE_INFO values(4,'账务账号');
insert into MODULE_INFO values(5,'业务账号');
insert into MODULE_INFO values(6,'账单管理');
insert into MODULE_INFO values(7,'报表');
最后这里表示个人信息和修改密码两项无论是什么权限都会显示。
<li><a href="user/user_info.html" class="information_off"></a></li> <li><a href="user/user_modi_pwd.html" class="password_off"></a></li>
以及通过使用
<c:choose> <c:when test="${currentModule==0 }"> <li><a href="${pageContext.request.contextPath }/login/toIndex.do" class="index_on"></a></li> </c:when> <c:otherwise> <li><a href="${pageContext.request.contextPath }/login/toIndex.do" class="index_off"></a></li> </c:otherwise> </c:choose>
因为之前在拦截器中将currentModule的值设置默认为0
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception { // 判断当前用户访问的模块 String url = request.getRequestURL().toString(); int currentModule = 0; // 默认0是NETCTOSS首页
添加一个点击返回首页的链接。
这样每个能显示的按钮,绑定一个链接跳转相应的页面,就实现了用户的权限管理。
posted on 2017-09-03 21:34 Loseheart 阅读(3725) 评论(0) 编辑 收藏 举报