在上一篇中, 我已经对 Shiro 中认证和授权模块基本认证做了介绍, 本篇主要介绍 Shiro 在 SSM 的工程中的整合使用方式和在 SpringBoot 工程中的使用方式。
接上篇: 谈谈 Shiro 的原理及在 SSM 和 SpringBoot 两种环境下的使用姿势 (上篇)
## 首先是在 SSM 工程中的整合
之前我们在 SSM 工程中作为身份认证和权限拦截的模块是通过拦截器的方式来实现的。现在我们去掉拦截器, 使用 Shiro 整合搭建工程。
- <!-- 这里需要配置一个Filter,将由Shiro实现 -->
- <filter>
- <filter-name>shiroFilter</filter-name>
- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
- <!-- 设置true由servlet容器控制filter的生命周期 -->
- <init-param>
- <param-name>targetFilterLifecycle</param-name>
- <param-value>true</param-value>
- </init-param>
- <!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean-->
- <init-param>
- <param-name>targetBeanName</param-name>
- <param-value>shiroFilter</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>shiroFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-config.dtd">
- <configuration>
- <!-- 定义 别名 -->
- <typeAliases>
- <package name="com.beautifulsoup.shiro.ssmdemo.entity"/>
- </typeAliases>
- </configuration>
- <!-- 配置Realm -->
- <bean id="shiroDemoRealm" class="com.beautifulsoup.shiro.ssmdemo.realm.ShiroDemoRealm"
- />
- <!-- 配置安全管理器 -->
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
- <property name="realm" ref="shiroDemoRealm" />
- </bean>
- <!-- Shiro 的Web过滤器 -->
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager" />
- <!-- 如果没有认证将要跳转的登陆地址 -->
- <property name="loginUrl" value="/login.action" />
- <!-- 没有权限跳转的地址 -->
- <property name="unauthorizedUrl" value="/refuse.jsp" />
- <property name="filterChainDefinitions">
- <value>
- /** = anon
- </value>
- </property>
- </bean>
为了简单, 我直接使用了上一次所介绍的 realm 类。
可以看到, 这里我们主要是配置了一个 ShiroFilterFactoryBean, 这是一个工厂类, 它主要用于生产 ShiroFilter, 我们可以在这个工厂 Bean 中定义一系列我们所需要的 Filter 链。Shiro 这个框架本身就为我们提供了很多的过滤器, 通过使用这些已经内置的过滤器已经能够很好的实现我们所需要实现的功能。上面我们配置的
表示对于该工程中所有的 url 都可以以匿名的方式来访问, anon 表示一个过滤器的缩写, 除此之外, Shiro 还提供了其他的一系列的过滤器。如下:
- /**=anon
- 过滤器简称 对应的实际过滤器
- anon org.apache.shiro.web.filter.authc.AnonymousFilter
- authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
- authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
- perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
- port org.apache.shiro.web.filter.authz.PortFilter
- rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
- roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
- ssl org.apache.shiro.web.filter.authz.SslFilter
- user org.apache.shiro.web.filter.authc.UserFilter
- logout org.apache.shiro.web.filter.authc.LogoutFilter
接下来, 我们就通过这些拦截器来实现我们 SSM 工程的认证和授权。
认证 代码在 (v0.3 标签下) 登录和退出: 配置如下:
- <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
- <property name="hashAlgorithmName" value="md5" />
- <property name="hashIterations" value="3" />
- </bean>
- <bean id="shiroDemoRealm" class="com.beautifulsoup.shiro.ssmdemo.realm.ShiroDemoRealm">
- <property name="credentialsMatcher" ref="credentialsMatcher">
- </property>
- </bean>
- <!-- 配置安全管理器 -->
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
- <property name="realm" ref="shiroDemoRealm" />
- </bean>
- <!-- Shiro 的Web过滤器 -->
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager" />
- <!-- 如果没有认证将要跳转的登陆地址 -->
- <property name="loginUrl" value="/login.action" />
- <!-- 没有权限跳转的地址 -->
- <property name="unauthorizedUrl" value="/refuse.jsp" />
- <property name="filterChainDefinitions">
- <value>
- <!-- 定义退出的路径 -->
- /logout.action = logout /** = authc
- </value>
- </property>
- </bean>
主要通过 FormAuthenticationFilter 实现。这里需要注意的是, 我们提交认证的表单的参数默认为 username 和 password, 记住我的参数默认为: rememberMe。原因如下:
注意, 当我们在系统中采用 FormAuthenticationFilter 作为配置时, FormAuthenticationFilter 会将表单的提交参数取出, 并调用 realm 进行认证。如果认证失败, 则系统自动跳转到我们配置的 loginUrl 的链接地址, 同时会将认证失败的异常信息添加到 request 中, 我们可以在 Controller 中定义一个方法接受 loginUrl 配置的链接地址, 然后从中取出异常信息进行二次处理。而如果我们认证成功了, 系统的成功处理器会默认跳转到我们将要访问的 url 路径。我们可以使用类似 loginUrl 的配置配置一个 successUrl 实现自定义的成功跳转逻辑。
授权:
代码在 v0.4 标签下
上面提到了, Shiro 的 web 模块主要是为我们提供了一系列的过滤器 Filter, 在传统的 ssm 项目整合过程中, 我们是通过将 Shiro 交给 Spring 进行管理然后在容器中配置一个过滤器链。
上面提到的认证是通过配置过滤器 FormAuthenticationFilter 完成的, 这里的授权是通过配置 PermissionsAuthorizationFilter 完成的。
配置如下:
- <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
- <property name="hashAlgorithmName" value="md5" />
- <property name="hashIterations" value="3" />
- </bean>
- <bean id="shiroDemoRealm" class="com.beautifulsoup.shiro.ssmdemo.realm.ShiroDemoRealm">
- <property name="credentialsMatcher" ref="credentialsMatcher">
- </property>
- </bean>
- <!-- 配置安全管理器 -->
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
- <property name="realm" ref="shiroDemoRealm" />
- </bean>
- <!-- Shiro 的Web过滤器 -->
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager" />
- <!-- 如果没有认证将要跳转的登陆地址 -->
- <property name="loginUrl" value="/login.action" />
- <!-- 没有权限跳转的地址 -->
- <property name="unauthorizedUrl" value="/refuse.action" />
- <property name="filterChainDefinitions">
- <value>
- <!-- 定义所需的权限信息 -->
- /item/query.action=perms[item:query] /item/delete02.action=perms[item:delete:02]
- <!-- 定义退出的路径 -->
- /logout.action = logout /** = authc
- </value>
- </property>
- </bean>
除了 xml 中的配置, shiro 还提供了注解的授权的方法。由于注解的授权方式本质上是 Spring 的 AOP 的代理方式, 所以我们需要在 Spring 的配置文件中开启 AOP 的支持。:
- <aop:config proxy-target-class="true"></aop:config>
- <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
- <property name="securityManager" ref="securityManager" />
- </bean>
- 在Controller中使用
- @RequestMapping("/delete02")
- @RequiresPermissions("item:delete:02")
- public String itemDelete(){
- return "delete02item";
- }
- @RequiresPermissions("item:query")
- @RequestMapping("/query")
- public String ItemQuery(){
- return "itemquery";
- }
我们在每次查询权限信息的时候, 控制台总会弹出警告:
这是提示我们没有添加缓存, 这会使得我们频繁查询数据库导致效率低下。在上一节的基本概念中也已经提到过几个重要的概念, 其中 CacheManager 就是实现缓存管理的, SessionManager 是实现的 Session 的管理。
这里我们使用 Shiro 整合 EhCache 来实现缓存的管理。
- <!-- 缓存管理器 -->
- <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
- <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
- </bean>
- ehcache的配置文件:
- <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
- <!--diskStore:缓存数据持久化的目录 地址 -->
- <diskStore path="D:\Temp" />
- <defaultCache
- maxElementsInMemory="1000"
- maxElementsOnDisk="10000000"
- eternal="false"
- overflowToDisk="false"
- diskPersistent="false"
- timeToIdleSeconds="120"
- timeToLiveSeconds="120"
- diskExpiryThreadIntervalSeconds="120"
- memoryStoreEvictionPolicy="LRU">
- </defaultCache>
- </ehcache>
Shiro 在 SSM 传统工程中的整合工程大多就这些, 下面简单说一下关于 SpringBoot 整合 Shiro 的使用方式。
## 然后是在 SpringBoot 工程中的整合:
SpringBoot 是对 Spring 传统项目的简化, 自然 Shiro 与 SpringBoot 的整合也是 Shiro 与 Spring 整合的简化。SpringBoot 与 Shiro 的整合类似于 SSM 工程与 Shiro 的整合。这里只介绍关于整合的不同之处。对于 SSM 的整合和 SpringBoot 整合的完整代码都已经上传 Github。
- 主要是将原来的XML中的配置提取到了Java配置中,核心的Java Config的类如下:
- @Bean("credentialMatcher")
- public CredentialMatcher credentialMatcher(){
- return new CredentialMatcher();
- }
- @Bean("authRealm")
- public AuthRealm authRealm(@Qualifier("credentialMatcher")CredentialMatcher matcher){
- AuthRealm authRealm=new AuthRealm();
- authRealm.setCredentialsMatcher(matcher);
- return authRealm;
- }
- @Bean("securityManager")
- public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm){
- DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
- securityManager.setRealm(authRealm);
- return securityManager;
- }
- @Bean
- public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")SecurityManager securityManager){
- ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
- shiroFilterFactoryBean.setSecurityManager(securityManager);
- shiroFilterFactoryBean.setLoginUrl("/login");
- shiroFilterFactoryBean.setSuccessUrl("/index");
- shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
- LinkedHashMap<String,String> filterChainDefinitionMap=new LinkedHashMap<>();
- filterChainDefinitionMap.put("/login","anon");
- filterChainDefinitionMap.put("/index","authc");
- filterChainDefinitionMap.put("/loginUser","anon");
- //filterChainDefinitionMap.put("/**","user");//配置shiro只要用户登录就可以查看所有url
- filterChainDefinitionMap.put("/admin", "roles[role3]");
- filterChainDefinitionMap.put("/edit", "perms[item:create:01]");
- shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
- return shiroFilterFactoryBean;
- }
- @Bean
- public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager")SecurityManager securityManager){
- AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
- advisor.setSecurityManager(securityManager);
- return advisor;
- }
- @Bean
- public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
- DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
- creator.setProxyTargetClass(true);
- return creator;
- }
这里可以看到, 其实 SpringBoot 中我们完全可以使用 Java 配置替代 XML 配置, 具体的整合思路还是一样的。
最后: ###SSM 整合 Shiro 的代码地址: github.com/fuyunwang/S…
###SpringBoot 整合 Shiro 的代码地址: github.com/fuyunwang/S…
如果对您有过帮助, 希望您随手一个 star。
来源: https://juejin.im/post/5a355bee51882538e2259a6c