使用shiro实现权限控制学习总结
2017-04-16 18:17
357 查看
参考了http://blog.csdn.net/frankcheng5143/article/details/50836619这篇文章。感谢GW_Cheng大神的启发。
参考shiro官方文档将shiro和spring集成。spring的基本配置默认都懂,不说了。项目用maven管理,这个也不细说了,大不了启动的时候看报错缺什么文件写什么依赖吧- -哈哈。后面我会做一个完整项目放在github上。
1、首先确定自己的权限方案是:为用户分配角色,角色拥有某种权限。而且是用数据库存储用户信息,包括用户资料、角色、权限信息。因此要建立5张表。分别是:
用户表,存储用户的相关信息
角色表,存储角色的相关信息
权限表,存储权限的相关信息
用户角色表,存储用户和角色的对应关系 一对多
角色权限表,存储角色和权限的对应关系 一对多
详情看大神的博客吧。
2、在web.xml中定义shiro的过滤器
2、spring-shiro.xml
这个文件会 import到spring的核心配置文件中。有人叫applicationcontext.xml,有人叫spring-core.xml……主要看自己习惯吧。反正web.xml里面写对了就能识别了。spring-core.xml里面记得配一个数据库连接池,druid、c3p0皆可。
3、springmvc配置,让springmvc控制权限认证后的跳转。
4、shiro的一些功能会用到缓存(比如remenber me),先配置好。(这一块我没有详细理解)
spring-cache.xml
ehcache.xml
配置部分到此结束,暂时没有用到MyBatis。
5、下面分析代码。主要是2个controller。
我们在shiro的配置里面使用默认的jdbcRealm,所以这个也不用自己写了,直接用。
登录的controller:
在其他的Controller中,使用注解来做权限控制访问。
当没有权限就去访问时,会抛出对应的异常。
6、学习心得体会。
1)文中查到一个用户之后,怎么知道他的权限呢?其过程是这样的:
jdbcrealm里面写了一些查询角色和授权的sql语句,在使用subject.login(token);登录之后就会自动根据数据库查到的信息,为用户分配角色和授权。
角色和权限实现的方式有很多种,文中只是方案之一。希望自己在未来深入了解之后,也能写出属于自己的解决方案吧。
2)在实现自定义的realm时(这个是后续学习的关键),可以使用mybatis来查数据库中的数据,自己做权限的分配。
3)密码如果使用了salt混淆来生成md5,jdbcRealm里面的相应配置我还没有弄清除具体怎么操作。如果saltStyle配了Column属性,sql数据库里user表似乎就要多加一列salt了。或者用external属性,将username作为salt。时间有限,先直接用没有混淆的MD5加密密码吧。
参考shiro官方文档将shiro和spring集成。spring的基本配置默认都懂,不说了。项目用maven管理,这个也不细说了,大不了启动的时候看报错缺什么文件写什么依赖吧- -哈哈。后面我会做一个完整项目放在github上。
1、首先确定自己的权限方案是:为用户分配角色,角色拥有某种权限。而且是用数据库存储用户信息,包括用户资料、角色、权限信息。因此要建立5张表。分别是:
用户表,存储用户的相关信息
角色表,存储角色的相关信息
权限表,存储权限的相关信息
用户角色表,存储用户和角色的对应关系 一对多
角色权限表,存储角色和权限的对应关系 一对多
详情看大神的博客吧。
2、在web.xml中定义shiro的过滤器
<!-- shiro的filter --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <!-- shiro的filter-mapping --> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2、spring-shiro.xml
这个文件会 import到spring的核心配置文件中。有人叫applicationcontext.xml,有人叫spring-core.xml……主要看自己习惯吧。反正web.xml里面写对了就能识别了。spring-core.xml里面记得配一个数据库连接池,druid、c3p0皆可。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <!-- 对应于web.xml中配置的那个shiroFilter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- Shiro的核心安全接口,这个属性是必须的 --> <property name="securityManager" ref="securityManager" /> <!-- 要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 --> <property name="loginUrl" value="/login.jsp" /> <!-- 登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码) --> <!-- <property name="successUrl" value="/" ></property> --> <!-- 用户访问未对其授权的资源时,所显示的连接。由Spring-MVC控制了,需要在spring-mvc配置文件中配跳转 --> <!-- <property name="unauthorizedUrl" value="/error/unauthorized" /> --> <property name="filterChainDefinitions"> <!-- WEB-INF/views/admin 文件夹下的所有jsp页面都需要授权才能访问 --> <value> /admin/**=authc </value> </property> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean> <!-- 数据库保存的密码是使用MD5算法加密的,所以这里需要配置一个密码匹配对象 --> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.Md5CredentialsMatcher"></bean> <!-- 缓存管理 --> <bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"></bean> <!-- 使用Shiro自带的JdbcRealm类 指定密码匹配所需要用到的加密对象 指定存储用户、角色、权限许可的数据源及相关查询语句 --> <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm"> <property name="credentialsMatcher" ref="credentialsMatcher"></property> <property name="permissions 4000 LookupEnabled" value="true"></property> <property name="dataSource" ref="dataSource"></property> <property name="authenticationQuery" value="SELECT password FROM sec_user WHERE user_name = ?"></property> <property name="userRolesQuery" value="SELECT role_name from sec_user_role left join sec_role using(role_id) left join sec_user using(user_id) WHERE user_name = ?"></property> <property name="permissionsQuery" value="SELECT permission_name FROM sec_role_permission left join sec_role using(role_id) left join sec_permission using(permission_id) WHERE role_name = ?"></property> </bean> <!-- Shiro安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="jdbcRealm"></property> <property name="cacheManager" ref="shiroCacheManager"></property> </bean> <!-- Shiro的注解配置一定要放在spring-mvc中 --> </beans>
3、springmvc配置,让springmvc控制权限认证后的跳转。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd "> <!-- 导入shiro的相关配置 --> <import resource="classpath:spring/spring-shiro.xml" /> <!-- 扫描路径 --> <context:component-scan base-package="com.test.controller"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> <!-- 配置根视图 --> <mvc:view-controller path="/" view-name="index" /> <!-- 激活基于注解的配置 @RequestMapping, @ExceptionHandler,数据绑定 ,@NumberFormat , @DateTimeFormat ,@Controller ,@Valid ,@RequestBody ,@ResponseBody等 --> <mvc:annotation-driven /> <!-- 静态资源配置 --> <mvc:resources location="/assets/" mapping="/assets/**"></mvc:resources> <!-- 视图层配置 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 开启shiro注解 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> <!-- 未认证或未授权时跳转必须在springmvc里面配,spring-shiro里的shirofilter配不生效 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <!--表示捕获的异常 --> <prop key="org.apache.shiro.authz.UnauthorizedException"> <!--捕获该异常时跳转的路径 --> /error/unauthorized </prop> <!--表示捕获的异常 --> <prop key="org.apache.shiro.authz.UnauthenticatedException"> <!--捕获该异常时跳转的路径 --> /error/unauthorized </prop> </props> </property> </bean> </beans>
4、shiro的一些功能会用到缓存(比如remenber me),先配置好。(这一块我没有详细理解)
spring-cache.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd"> <cache:annotation-driven cache-manager="cacheManager"/> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache"/> <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:ehcache.xml"/> </beans>
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd"> <diskStore path="java.io.tmpdir/ehcache" /> <!-- 默认缓存 --> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" /> <!-- 配置自定义缓存 maxElementsInMemory:缓存中允许创建的最大对象数 eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。 timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前, 两次访问时间的最大时间间隔值,这只能在元素不是永久驻留时有效, 如果该值是 0 就意味着元素可以停顿无穷长的时间。 timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值, 这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。 overflowToDisk:内存不足时,是否启用磁盘缓存。 memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。 --> <!-- userService查询用户的缓存 --> <cache name="userIsExists" maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" memoryStoreEvictionPolicy="LRU" /> <!-- userService查询用户的缓存 --> <cache name="getUserById" maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" memoryStoreEvictionPolicy="LRU" /> </ehcache>
配置部分到此结束,暂时没有用到MyBatis。
5、下面分析代码。主要是2个controller。
我们在shiro的配置里面使用默认的jdbcRealm,所以这个也不用自己写了,直接用。
登录的controller:
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); token.setRememberMe(true); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); if (subject.isAuthenticated()) { request.getSession().setAttribute("user",user); SavedRequest savedRequest = WebUtils.getSavedRequest(request); // 获取保存的URL if (savedRequest == null || savedRequest.getRequestUrl() == null) { return "admin/home"; } else { return "forward:" + savedRequest.getRequestUrl(); } } else { return "login"; } } catch (IncorrectCredentialsException e) { msg = "登录密码错误. Password for account " + token.getPrincipal() + " was incorrect."; model.addAttribute("message", msg); System.out.println(msg); }
在其他的Controller中,使用注解来做权限控制访问。
// 只用同时具有user:view和user:create权限才能访问 @RequiresPermissions(value = { "user:view", "user:create" }, logical = Logical.AND) @RequestMapping(value = "/admin/auth") public String adminWithAuth() { return "admin/withauth"; }
当没有权限就去访问时,会抛出对应的异常。
6、学习心得体会。
1)文中查到一个用户之后,怎么知道他的权限呢?其过程是这样的:
<bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm"> <property name="credentialsMatcher" ref="credentialsMatcher"></property> <property name="permissionsLookupEnabled" value="true"></property> <property name="dataSource" ref="dataSource"></property> <property name="authenticationQuery" value="SELECT password FROM sec_user WHERE user_name = ?"></property> <property name="userRolesQuery" value="SELECT role_name from sec_user_role left join sec_role using(role_id) left join sec_user using(user_id) WHERE user_name = ?"></property> <property name="permissionsQuery" value="SELECT permission_name FROM sec_role_permission left join sec_role using(role_id) left join sec_permission using(permission_id) WHERE role_name = ?"></property> </bean>
jdbcrealm里面写了一些查询角色和授权的sql语句,在使用subject.login(token);登录之后就会自动根据数据库查到的信息,为用户分配角色和授权。
角色和权限实现的方式有很多种,文中只是方案之一。希望自己在未来深入了解之后,也能写出属于自己的解决方案吧。
2)在实现自定义的realm时(这个是后续学习的关键),可以使用mybatis来查数据库中的数据,自己做权限的分配。
3)密码如果使用了salt混淆来生成md5,jdbcRealm里面的相应配置我还没有弄清除具体怎么操作。如果saltStyle配了Column属性,sql数据库里user表似乎就要多加一列salt了。或者用external属性,将username作为salt。时间有限,先直接用没有混淆的MD5加密密码吧。
相关文章推荐
- 使用shiro实现权限控制学习总结
- cakephp学习:大部分动作使用Auth组件来控制权限,但少部分不用,如何实现?
- 在前后端分离的项目中,后台使用shiro框架时,怎样使用它的会话管理系统(session),从而实现权限控制
- Spring Cloud与微服务学习总结(5)——认证鉴权与API权限控制在微服务架构中的设计与实现(三)
- 使用Shiro进行权限控制的实现流程
- Spring Cloud与微服务学习总结(4)——认证鉴权与API权限控制在微服务架构中的设计与实现(二)
- Spring Cloud与微服务学习总结(6)——认证鉴权与API权限控制在微服务架构中的设计与实现(四)
- 使用shiro实现权限的控制
- Spring Cloud与微服务学习总结(3)——认证鉴权与API权限控制在微服务架构中的设计与实现(一)
- 使用Shiro 集合Spring来实现权限控制
- 使用spring的ProxyFactoryBean来实现权限控制
- 使用ACEGI实现权限控制,第一部分
- ssh项目整合shiro时,在struts2的action中使用shiro的注解进行权限控制时,NoSuchMethodException:com.sun.proxy.$Proxy26
- Struts2使用Interceptor实现权限控制的应用实例详解
- Asp.net下使用HttpModule模拟Filter,实现权限控制
- 一款二级菜单和使用自定义标签实现简单权限控制
- 使用express+mongoDB搭建多人博客 学习(5)权限控制
- Asp.net下使用HttpModule模拟Filter,实现权限控制
- Shiro 权限框架使用总结
- Shiro QuickStart使用shiro.ini静态数据源实现权限管理