现在各个企业管理网站对登录的账号都要进行权限管理,并且相当重要,每个账号登录进去所能看到的东西大不相同,下面是实现该功能的一个的一种方法。
需求:
权限:权限是使用者操作系统中功能模块的能力,如“角色管理”模块、“资费管 理”模块和“账单管理”模块等。通过指定权限,可将使用者的操作限定在指定的 范围内,以保证操作的安全。
例如,一个使用者拥有“资费管理”权限,表示该使 用者可以操作“资费管理”模块,以执行资费管理的操作。权限由 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 location="classpath:jdbc.properties"/>
2
3 <!-- 定义数据源 -->
4 <bean
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>
xml配置文件中设置
Step3、其他xml文件中的设置(包含拦截器等):
1 <bean 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
59 class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
60 <property name="dataSource" ref="ds" />
61 </bean>
62 <tx:advice 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
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" >
65 <table>
66 <tr>
67 <td class="login_info">账号:</td>
68 <td colspan="2">
69 <input type="text" name="adminCode" class="width150" οnfοcus="set_msg('admin_code_msg','30长度的字母、数字和下划线');"/>
70 </td>
71 <td class="login_error_info"><span class="required" >30长度的字母、数字和下划线</span></td>
72 </tr>
73 <tr>
74 <td class="login_info">密码:</td>
75 <td colspan="2">
76 <input type="password" name="password" class="width150" οnfοcus="set_msg('password_msg','30长度的字母、数字和下划线');"/>
77 </td>
78 <td><span class="required" >30长度的字母、数字和下划线</span></td>
79 </tr>
80 <tr>
81 <td class="login_info">验证码:</td>
82 <td class="width70"><input name="code" type="text" class="width70" οnfοcus="set_msg('code_msg','');"/></td>
83 <td><img src="createImage.do" alt="验证码" title="点击更换" οnclick="change();"/></td>
84 <td><span class="required" ></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 >
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" οnlοad="startTimes();">
<h1 >
您无权访问此页面, <span >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 }
View Code
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 }
View Code
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 }
View Code
业务实现逻辑:
step1 用户登录
首先当用户访问toLogin.do时,
@RequestMapping("/toLogin.do")
public String toLogin() {
return "main/login";
}
这时用户在login.jsp生成的页面中填写账号密码和验证码,填写完毕后提交。
<form action="login.do" method="post" >
这时将跳转至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
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首页
添加一个点击返回首页的链接。
这样每个能显示的按钮,绑定一个链接跳转相应的页面,就实现了用户的权限管理。