首页 > 其他分享 >SpringMVC整合Shiro权限框架

SpringMVC整合Shiro权限框架

时间:2023-11-08 17:37:49浏览次数:35  
标签:return SpringMVC jsp Shiro import 权限 shiro user


最近在学习Shiro,首先非常感谢开涛大神的《 跟我学Shiro》系列,在我学习的过程中发挥了很大的指导作用。学习一个新的东西首先就是做一个demo,多看不如多敲,只有在实践中才能发现自己的欠缺,下面记录下来我整合shiro的过程。如果有不足之处,还望各位看官多多指出。

一、基本名词解释

Apache Shiro是一个强大易用的Java安全框架。它可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存、单点登录等等,而且它的API也十分简洁易用,所以现在有很多人都在使用它。它的基本能功能点如图所示:

SpringMVC整合Shiro权限框架_xml

从图上我们可以看出Shiro的四大核心功能:

Authentication(身份验证):简称为“登录”,即证明用户是谁。
Authorization(授权):访问控制的过程,即决定是否有权限去访问受保护的资源。
Session Management(会话管理):管理用户特定的会话,即使在非 Web 或 EJB 应用程序。
Cryptography(加密):通过使用加密算法保持数据安全

我们同时也可以看看Shiro的架构长什么样子:

SpringMVC整合Shiro权限框架_spring_02

同样的虚线框框圈着的是Shiro3大核心组件:

Subject :正与系统进行交互的人,或某一个第三方服务。所有 Subject  实例都被绑定到(且这是必须的)一个SecurityManager 上。
SecurityManager:Shiro 架构的心脏,用来协调内部各安全组件,管理内部组件实例,并通过它来提供安全管理的各种服务。当 Shiro 与一个 Subject  进行交互时,实质上是幕后的 SecurityManager  处理所有繁重的 Subject 安全操作。
Realms :本质上是一个特定安全的 DAO。当配置 Shiro  时,必须指定至少一个 Realm  用来进行身份验证和/或授权。Shiro 提供了多种可用的 Realms 来获取安全相关的数据。如关系数据库(JDBC),INI 及属性文件等。可以定义自己 Realm  实现来代表自定义的数据源。

以上是些基本的名称解释。如需要查看更详细的请参考开涛大神的博客。

二、准备工作

整合程序沿用之前的例子Maven+spring+Spring MVC+MyBatis+MySQL整合SSM框架,现在我们需要在此基础上继续整合进Shiro。

三、开始整合

1.加入jar包

整合demo用的是maven对依赖进行管理。我们需要在pom.xml里加上配置:


1. <dependency>
2. <groupId>com.alibaba</groupId>
3. <artifactId>fastjson</artifactId>
4. <version>1.1.32</version>
5. </dependency>
6. <dependency>
7. <groupId>org.apache.shiro</groupId>
8. <artifactId>shiro-core</artifactId>
9. <version>1.2.2</version>
10. </dependency>
11. <dependency>
12. <groupId>org.apache.shiro</groupId>
13. <artifactId>shiro-web</artifactId>
14. <version>1.2.2</version>
15. </dependency>
16. <dependency>
17. <groupId>org.apache.shiro</groupId>
18. <artifactId>shiro-spring</artifactId>
19. <version>1.2.2</version>
20. </dependency>
21. <dependency>
22. <groupId>org.apache.shiro</groupId>
23. <artifactId>shiro-ehcache</artifactId>
24. <version>1.2.2</version>
25. </dependency>


里面我加入了阿里的fastjson。我用fastjson替换了jackson(理由:没有什么理由,就是喜欢用了.....)

2.spring-mvc.xml的配置

这是替换掉jackson的配置


1. <mvc:annotation-driven>
2. <mvc:message-converters>
3. <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
4. <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
5. <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
6. <!--<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />-->
7. <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter" />
8. </mvc:message-converters>
9. </mvc:annotation-driven>
10. <mvc:default-servlet-handler />
11.       
12.   
13. <!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
14. <!-- 支持JSON数据格式 -->
15. <bean
16. class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
17. <property name="messageConverters">
18. <list>
19. <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/><!-- 解析导出文件byte流 -->
20. <ref bean="fastJsonHttpMessageConverter" />
21. <!-- 
22.                 <ref bean="mappingJacksonHttpMessageConverter" />
23.      -->
24. </list>
25. </property>
26. </bean>
27. <bean id="mappingJacksonHttpMessageConverter"
28. class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
29. </bean>-->
30. <!-- 使用fastJson来支持JSON数据格式 -->
31. <bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
32. <property name="supportedMediaTypes">
33. <list>
34. <value>text/html;charset=UTF-8</value>
35. <value>application/json</value>
36. </list>
37. </property>
38. <property name="features">
39. <list>
40. <value>WriteMapNullValue</value>
41. <value>QuoteFieldNames</value>
42. </list>
43. </property>
44. </bean>


3.首先先配置Shiro Filter(web.xml)

1. <!-- 配置  Shiro 的 Filter -->
2. <filter>
3. <description>shiro 权限拦截</description>
4. <filter-name>shiroFilter</filter-name>
5. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
6. <init-param>
7. <param-name>targetFilterLifecycle</param-name>
8. <param-value>true</param-value>
9. </init-param>
10. </filter>
11. <filter-mapping>
12. <filter-name>shiroFilter</filter-name>
13. <url-pattern>/*</url-pattern>
14. </filter-mapping>

4.创建Shiro的配置文件spring-shiro(注:这边统一起名为spring-*.xml,然后可以在配置contextConfigLocation时使用通配符了)


1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
5. <!-- 启用shrio授权注解拦截方式 -->
6. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
7. <!-- 装配 securityManager -->
8. <property name="securityManager" ref="securityManager"/>
9. <!-- 配置登陆页面 -->
10. <property name="loginUrl" value="/index.jsp"/>
11. <!-- 登陆成功后的一面 -->
12. <property name="successUrl" value="/jsp/success.jsp"/>
13. <span style="white-space:pre">    </span><property name="unauthorizedUrl" value="/jsp/unauthorized.jsp"/>
14. <!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截.  -->
15. <property name="filterChainDefinitions">
16. <value>
17. index.jsp=anon
18. success.jsp=anon
19. fail.jsp=anon
20. user.jsp = roles[user]  
21. admin.jsp = roles[admin]  
22. logout = logout
23. </value>
24. </property>
25. </bean>
26.   
27. <!-- 配置缓存管理器 -->
28. <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
29. <!-- 指定 ehcache 的配置文件 -->
30. <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
31. </bean>
32. <!-- 配置进行授权和认证的 Realm -->
33. <bean id="myRealm" class="com.gray.base.shiro.ShiroDbRealm">
34. <property name="userService" ref="userService" />
35. </bean>
36. <bean id="userService" class="com.gray.user.service.impl.UserServiceImpl" />
37. <!-- 配置 Shiro 的 SecurityManager Bean. -->
38. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
39. <property name="cacheManager" ref="cacheManager"/>
40. <property name="realm" ref="myRealm"/>
41. <property name="sessionMode" value="native">
42. </property>
43. </bean>
44. <!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. -->
45. <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
46. </beans>


5.数据库及页面设计好了。以上就是所有整合Shiro所需要配置的东西,下面我们开始写程序,为了方便,数据库我沿用之前的user表,将它进行了小小的改造,在实际项目中 对角色和权限的控制需要在定义多张表的。helloworld程序就将就着用了。sql语句如下:CREATE TABLE `user` ( `username` varchar(40) NOT NULL, `password` varchar(40) NOT NULL, `age` int(3) DEFAULT NULL, `name` varchar(40) DEFAULT NULL, `role` varchar(40) DEFAULT NULL, PRIMARY KEY (`username`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; 表结构定义完后需要写实体类,这里就不贴代码了。jsp页面如图所示: 

SpringMVC整合Shiro权限框架_spring_03

success.jsp

在这里我加入了Shiro的标签来控制页面的显示。其他的jsp就不一一列出代码了。

1. <%@ page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8"%>
2. <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
3.   
4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
5. <html>
6. <head>
7. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
8. <title></title>
9. </head>
10. <body>
11. ${successMsg } Welcome!  <shiro:principal/>
12. <br><br>
13.       
14. <shiro:hasAnyRoles name="user">
15. <a href="/jsp/user.jsp">User Page</a>
16. </shiro:hasAnyRoles>
17.       
18. <br><br>
19.       
20. <shiro:hasAnyRoles name="admin">
21. <a href="/jsp/admin.jsp">Admin Page</a>
22. </shiro:hasAnyRoles>
23.       
24. <br><br>
25. <a href="../test/logout.do">Logout</a>
26. </body>
27. </html>

6.后台代码的编写

6.1 Controller层的编写


这次整合我么主要要实现登陆和登出功能,因此controller层我们这样写:


1. package
2.   
3. import
4.   
5. import
6. import
7.   
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16. import
17. import
18.   
19. import
20. import
21.   
22. @Controller
23. @RequestMapping("/test")   
24. public class
25. @Autowired
26. private
27.   
28. @RequestMapping("/dologin.do") //url
29. public
30.     String info = loginUser(user);  
31. if (!"SUCC".equals(info)) {  
32. "failMsg", "用户不存在或密码错误!");  
33. return "/jsp/fail";  
34. else{  
35. "successMsg", "登陆成功!");//返回到页面说夹带的参数
36. "name", user.getUsername());  
37. return "/jsp/success";//返回的页面
38.     }  
39.   }  
40.   
41. @RequestMapping("/logout.do")  
42. public void logout(HttpServletRequest request,HttpServletResponse response) throws
43.     Subject subject = SecurityUtils.getSubject();  
44. if (subject != null) {  
45. try{  
46.             subject.logout();  
47. catch(Exception ex){  
48.         }  
49.     }  
50. "/index.jsp");  
51. }  
52.   
53. private
54. if (isRelogin(user)) return "SUCC"; // 如果已经登陆,无需重新登录
55.           
56. return shiroLogin(user); // 调用shiro的登陆验证
57. }  
58. private
59. // 组装token,包括客户公司名称、简称、客户编号、用户名称;密码
60. new UsernamePasswordToken(user.getUsername(), user.getPassword().toCharArray(), null);   
61. true);  
62.       
63. // shiro登陆验证
64. try
65.         SecurityUtils.getSubject().login(token);  
66. catch
67. return "用户不存在或者密码错误!";  
68. catch
69. return "用户不存在或者密码错误!";  
70. catch
71. return ex.getMessage(); // 自定义报错信息
72. catch
73.         ex.printStackTrace();  
74. return "内部错误,请重试!";  
75.     }  
76. return "SUCC";  
77. }  
78.   
79. private boolean
80.     Subject us = SecurityUtils.getSubject();  
81. if
82. return true; // 参数未改变,无需重新登录,默认为已经登录成功
83.         }  
84. return false; // 需要重新登陆
85. }  
86. }

6.2 实现自定义Realm


shiro从Realm获取安全数据,也就是说SecurityManager要验证身份,它需要从Realm获取相应的用户进行比较以确定用户的身份是否合法;我们可以把Realm看作是DataSource,安全数据源。实现自定义Realm主要是继承AuthrizingRealm这个父类,重写doGetAuthrizationInfo和doGetAuthenticationInfo这两个方法,其中doGetAuthenticationInfo是用来验证用户合法性的,根据输入的用户信息从数据库中查出用户,根据用户情况抛出不同的异常。doGetAuthrizationInfo是对当前用的用户进行授权的。在这里我把角色写死了。在实际项目开发中应该是在表中做权限和角色的定义再从数据库中查出一个集合然后迭代授权。

具体实现代码如下:

1. package
2.    
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15.   
16. import
17. import
18.   
19. public class ShiroDbRealm extends
20. @Autowired
21. private
22. public static final String SESSION_USER_KEY = "gray";  
23.   
24. /**
25.      * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法
26.      */
27. @Override
28. protected
29.         User user = (User) SecurityUtils.getSubject().getSession().getAttribute(ShiroDbRealm.SESSION_USER_KEY);  
30. new
31.         info.addRole(user.getRole().trim());  
32. return
33.     }  
34.   
35. /**
36.      * 认证回调函数,登录信息和用户验证信息验证
37.      */
38. @Override
39. protected
40. throws
41. // 把token转换成User对象
42.         User userLogin = tokenToUser((UsernamePasswordToken) authcToken);  
43. // 验证用户是否可以登录
44.         User ui = userService.doUserLogin(userLogin);  
45. if(ui == null)  
46. return null; // 异常处理,找不到数据
47. // 设置session
48.         Session session = SecurityUtils.getSubject().getSession();  
49.         session.setAttribute(ShiroDbRealm.SESSION_USER_KEY, ui);   
50. //当前 Realm 的 name
51. this.getName();  
52. //登陆的主要信息: 可以是一个实体类的对象, 但该实体类的对象一定是根据 token 的 username 查询得到的.
53. //      Object principal = ui.getUsername();
54.         Object principal = authcToken.getPrincipal();  
55. return new
56.     }  
57.   
58. private
59. new
60.         user.setUsername(authcToken.getUsername());  
61.         user.setPassword(String.valueOf(authcToken.getPassword()));  
62. return
63.     }  
64.   
65. //一定要写getset方法
66. public
67. return
68.     }  
69.   
70. public void
71. this.userService = userService;  
72.     }  
73. }

  

在这里我们要注意的是用

注解没办法注入我们要的service,一定要写getset方法,不然会报错(网上的解决办法挺有道理的但是试过没效果。。。。)。

具体的serviceImpl的实现我就不写出来了,数据库的查询我相信大家都会(默认你们都会)。随后如果有需要我会把整合代码放上来。

最后贴几张测试图:

登陆界面:

SpringMVC整合Shiro权限框架_xml_04



以管理员角色的账号登陆:


SpringMVC整合Shiro权限框架_spring_05


AdminPage:


SpringMVC整合Shiro权限框架_html_06


以普通用户角色的账号登陆:


SpringMVC整合Shiro权限框架_xml_07


UserPage:


SpringMVC整合Shiro权限框架_spring_08


当你以普通用户登录却想访问adminpage时:


SpringMVC整合Shiro权限框架_html_09


登陆失败:


SpringMVC整合Shiro权限框架_xml_10


最后登出点击logout返回登陆主界面。


以上就是整合Shiro的所有过程,当然在实际项目中不会那么简单但我觉得原理也是差不多的。学无止境,最后再次感谢网上提供资料的各位大神。




标签:return,SpringMVC,jsp,Shiro,import,权限,shiro,user
From: https://blog.51cto.com/u_809530/8256758

相关文章

  • Linux安装Java环境变量及配置分配用户权限
    1wget安装yum-yinstallwget2.下载wget--no-cookies--no-check-certificate--header"Cookie:gpw_e24=http%3A%2F%2Fwww.oracle.com%2F;oraclelicense=accept-securebackup-cookie""http://download.oracle.com/otn-pub/java/jdk/8u141-b15/336fa29ff2bb......
  • Linux文件权限设置(1)
    Linux文件权限设置(1)总述:Linux系统一般将文件可存/取访问的身份分为3个类别:owner(所有者)、group(所属组)、others(其他),且3种身份各有read(读)、write(写)、execute(执行)等权限。1、权限介绍什么是权限?在多用户(可以不同时)计算机系统的管理中,权限是指某个特定的用户具有特定的系统资源使......
  • 权限菜单管理上
    因为要考软考,花了些时间准备软考,权限管理拉下了,今天学了学。现在只是雏形。   ......
  • kkfileview部署遇到的问题---权限
    运行了一段时间的在线预览,程序突然就启动不起来了,想着重新部署也比较简单,就重新部署吧,然后就开始一系列问题:一、基础环境(1检测kkfileview需要的基础软件是否完备OpenOffice无法打开,基本确定是OpenOffice问题;(2j jdk环境正常; 二、安装OpenOffice (1、卸载OpenOffice; ......
  • javaWeb&springMVC
    Servlet1:servlet定义servlet是开发动态web的一门技术,通过servlet实现与用户的动态交互。2:使用方式(1)javaWeb中只需要继承HttpServlet接口,重写其中的doGet和doPost方法即可编写一个servlet;写好servlet程序后需要在web.xml文件中编写映射,相当于将我们缩写的servlet注册到web服务......
  • 第四章 文件权限(一)
     4.1基本权限UGO:4.1.1设置文件属性与权限:在Linux系统中,每个文件和目录都有一组权限,用于控制对其的访问。这些权限被分为三个类别:用户(User)、组(Group)和其他人(Others)。每个类别都有三种权限:读取权限(R)、写入权限(W)和执行权限(X)。读取权限(R):允许用户查看文件内容或......
  • 关于文件夹权限不够,引起的安装错误的处理方法
      文件夹没有权限,在更改文件夹的权限的时候会报各种错误,很多人在一报错的情况下,都不知道如何设置了。今天给大家带来一个用命令来处理这个问题的方法:假设文件路径为:C:\Windows\System32\en-US  比如:在安装软件的时候,报这个错误:用上面的设置文件权限的方法又报错的情况......
  • SpringMVC 依赖
    <?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0ht......
  • 11、SpringMVC之文件下载和上传
    创建名为spring_mvc_file的新module,过程参考9.1节和9.5节11.1、文件下载11.1.1、创建图片目录并放置图片11.1.2、页面请求示例<ath:href="@{/test/down}">下载图片</a>11.1.3、控制器方法示例packageonline.liaojy.controller;importorg.springframework.http.Ht......
  • 账号和权限管理
    目录账号和权限管理账号管理1.基本概念Linux安全模型2.用户2.1基本概念2.2用户账号文件2.3用户密码文件2.4创建用户账号useradd原理格式选项用法2.5设置用户密码passwd选项用法2.6修改已有用户的密码信息chage用法2.7修改用户账号已有属性usermod选项用法2.8删......