第八讲 shiro 整合 ssm

1、整合ssm并且实现用户登录和菜单权限

2、将shiro整合到ssm中

  (1)添加shiro相关jar包

  (2)在web.xml中添加shiro配置

 1     <!-- 新增shiro配置 -->
 2     <!-- 配置shiroFilter,通过代理来配置,对象由spring容器来创建的,但是交由servlet容器来管理 -->
 3     <filter>
 4         <filter-name>shiroFilter</filter-name>
 5         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 6         <init-param>
 7             <!-- 表示bean的生命周期由servlet管理 -->
 8             <param-name>targetFilterLifecycle</param-name>
 9             <param-value>true</param-value>
10         </init-param>
11 
12         <init-param>
13             <!-- 表示在spring容器中bean的id,如果不配置该属性,那么默认和filter的name一致 -->
14             <param-name>targetBeanName</param-name>
15             <param-value>shiroFilter</param-value>
16         </init-param>
17 
18     </filter>
19 
20     <filter-mapping>
21         <filter-name>shiroFilter</filter-name>
22         <url-pattern>/*</url-pattern>
23     </filter-mapping>
24 
25     <!-- shiro结束 -->

  (3)添加applicationContext-shiro.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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 配置securityManager -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 当访问需要认证的资源时,如果没有认证,那么将自动跳转到该url;
        如果不配置该属性,默认情况下货到根路径下的login.jsp -->
        <!-- controller层查看地址配置 -->
        <property name="loginUrl" value="/login"></property>
        <!-- 配置认证成功后,跳转到那个url上,通常不设置,如果不设置,那么默认认证成功后跳转到上一个url -->
        <property name="successUrl" value="/index"></property>
        <!-- 配置用户没有权限访问资源时,跳转的页面     /refuse自定义 -->
        <property name="unauthorizedUrl" value="/refuse"></property>
        <!-- 配置shiro的过滤器链 -->
        <property name="filterChainDefinitions">
            <value>
                <!-- anon表示匿名 -->
                /toLogin=anon
                /login=authc
                /logout=logout

           /js/**=anon
           /css/**=anon
           /images/**=anon

                /**=authc
            </value>
        </property>
    </bean>
    
    <!-- 配置securityManager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"/>
    </bean>
    
    <bean id="userRealm" class="com.sun123.template.realm.UserRealm"/>
    
    
</beans>

  (4)修改LoginController中的登录方法

package com.sun123.template.conrtroller;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class LoginController {

    @RequestMapping(value = {"/","index"})
    public ModelAndView index() {
        return new ModelAndView("index");
    }
    
    //去登录页面
    @RequestMapping("/toLogin")
    public ModelAndView toLogin() {
        return new ModelAndView("login");
    }
    
    //登录
    @RequestMapping("/login")
    public ModelAndView login(HttpServletRequest request) {
        System.out.println("========login=======");
        ModelAndView mv = new ModelAndView("login");
        String className = (String)request.getAttribute("shiroLoginFailure");
        if (UnknownAccountException.class.getName().equals(className)) {
            //抛出自定义异常
            mv.addObject("msg","用户名或密码错误");
        }else if (IncorrectCredentialsException.class.getName().equals(className)) {
            //抛出自定义异常
            mv.addObject("msg","用户名或密码错误");
        } else {
            //抛出自定义异常
            mv.addObject("msg","系统异常");
        }
        
        return mv;
        
    }
    
    //访问被拒绝
    @RequestMapping("/refuse")
    public ModelAndView refuse() {
        return new ModelAndView("refuse");
    }
}

  (5)添加自定义Realm:UserRealm.java

package com.sun123.template.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class UserRealm extends AuthorizingRealm {

    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return "userRealm";
    }
    
    //获取认证信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("---------认证----------------");
        String username = token.getPrincipal().toString();
        String pwd = "1111";
        
        return new SimpleAuthenticationInfo(username,pwd,getName());
    }
    
    //获取授权信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        
        
        return null;
    }

    

}

3、修改UserRealm实现自定义认证

 1 package com.sun123.template.realm;
 2 
 3 import org.apache.shiro.authc.AuthenticationException;
 4 import org.apache.shiro.authc.AuthenticationInfo;
 5 import org.apache.shiro.authc.AuthenticationToken;
 6 import org.apache.shiro.authc.SimpleAuthenticationInfo;
 7 import org.apache.shiro.authz.AuthorizationInfo;
 8 import org.apache.shiro.realm.AuthorizingRealm;
 9 import org.apache.shiro.subject.PrincipalCollection;
10 import org.springframework.beans.factory.annotation.Autowired;
11 
12 import com.sun123.template.entity.User;
13 import com.sun123.template.service.UserService;
14 
15 public class UserRealm extends AuthorizingRealm {
16 
17     @Autowired
18     private UserService userService;
19     
20     @Override
21     public String getName() {
22         // TODO Auto-generated method stub
23         return "userRealm";
24     }
25     
26     //获取认证信息
27     @Override
28     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
29         System.out.println("---------认证----------------");
30         String username = token.getPrincipal().toString();
31         User user = userService.findByUserName(username); 
32         return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
33     }
34     
35     //获取授权信息
36     @Override
37     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
38 
39         return null;
40     }
41 
42     
43 
44 }

4、凭证匹配器配置

 1     <!-- 配置自定义realm -->
 2     <bean id="userRealm" class="com.sun123.template.realm.UserRealm">
 3         <property name="credentialsMatcher" ref="credentialsMatcher" />
 4     </bean>
 5     <!-- 配置凭证匹配器 -->
 6     <bean id="credentialsMatcher"
 7         class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
 8         <property name="hashAlgorithmName" value="md5" />
 9         <!-- 迭代次数 -->
10         <property name="hashIterations" value="2" />
11     </bean>

  UserRealm.java要相应改变

 1 package com.sun123.template.realm;
 2 
 3 import org.apache.shiro.authc.AuthenticationException;
 4 import org.apache.shiro.authc.AuthenticationInfo;
 5 import org.apache.shiro.authc.AuthenticationToken;
 6 import org.apache.shiro.authc.SimpleAuthenticationInfo;
 7 import org.apache.shiro.authz.AuthorizationInfo;
 8 import org.apache.shiro.realm.AuthorizingRealm;
 9 import org.apache.shiro.subject.PrincipalCollection;
10 import org.apache.shiro.util.ByteSource;
11 import org.springframework.beans.factory.annotation.Autowired;
12 
13 import com.sun123.template.entity.User;
14 import com.sun123.template.service.UserService;
15 
16 public class UserRealm extends AuthorizingRealm {
17 
18     @Autowired
19     private UserService userService;
20     
21     @Override
22     public String getName() {
23         // TODO Auto-generated method stub
24         return "userRealm";
25     }
26     
27     //获取认证信息
28     @Override
29     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
30         System.out.println("---------认证----------------");
31         String username = token.getPrincipal().toString();
32         User user = userService.findByUserName(username); 
33         return new SimpleAuthenticationInfo(user,user.getPassword(),ByteSource.Util.bytes(user.getPasswordSalt()),getName());
34     }
35     
36     //获取授权信息
37     @Override
38     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
39 
40         return null;
41     }
42 
43     
44 
45 }

5、logout配置,默认退出后跳转到根路径下,如果需要改变则需重新配置logout过滤器,过滤器的id不能改变,只能为logout

 1     <bean id="shiroFilter"
 2         class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
 3         <!-- 配置securityManager -->
 4         <property name="securityManager" ref="securityManager" />
 5         <!-- 当访问需要认证的资源时,如果没有认证,那么将自动跳转到该url; 如果不配置该属性,默认情况下货到根路径下的login.jsp -->
 6         <!-- controller层查看地址配置 -->
 7         <property name="loginUrl" value="/login"></property>
 8         <!-- 配置认证成功后,跳转到那个url上,通常不设置,如果不设置,那么默认认证成功后跳转到上一个url -->
 9         <property name="successUrl" value="/index"></property>
10         <!-- 配置用户没有权限访问资源时,跳转的页面 /refuse自定义 -->
11         <property name="unauthorizedUrl" value="/refuse"></property>
12         <!-- 配置shiro的过滤器链
13             logout默认退出后跳转到根路径下,可以重新指定
14          -->
15         <property name="filterChainDefinitions">
16             <value>
17                 <!-- anon表示匿名 -->
18                 /toLogin=anon
19                 /login=authc
20                 /logout=logout
21                 /js/**=anon
22                 /css/**=anon
23                 /images/**=anon
24                 /**=authc
25             </value>
26         </property>
27     </bean>
28 
29     <!-- 配置authc过滤器(用户名和密码不使用默认配置username,password) -->
30     <bean id="authc" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
31         <property name="usernameParam" value="name"/>
32         <property name="passwordParam" value="pwd"/>
33     </bean>
34     
35     <!-- 配置logout过滤器 -->
36     <bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter">
37         <property name="redirectUrl" value="/toLogin"/>
38     </bean>

6、改变登录时的表单域名称,需要重新配置authc过滤器

 1     <bean id="shiroFilter"
 2         class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
 3         <!-- 配置securityManager -->
 4         <property name="securityManager" ref="securityManager" />
 5         <!-- 当访问需要认证的资源时,如果没有认证,那么将自动跳转到该url; 如果不配置该属性,默认情况下货到根路径下的login.jsp -->
 6         <!-- controller层查看地址配置 -->
 7         <property name="loginUrl" value="/login"></property>
 8         <!-- 配置认证成功后,跳转到那个url上,通常不设置,如果不设置,那么默认认证成功后跳转到上一个url -->
 9         <property name="successUrl" value="/index"></property>
10         <!-- 配置用户没有权限访问资源时,跳转的页面 /refuse自定义 -->
11         <property name="unauthorizedUrl" value="/refuse"></property>
12         <!-- 配置shiro的过滤器链
13             logout默认退出后跳转到根路径下,可以重新指定
14          -->
15         <property name="filterChainDefinitions">
16             <value>
17                 <!-- anon表示匿名 -->
18                 /toLogin=anon
19                 /login=authc
20                 /logout=logout
21                 /js/**=anon
22                 /css/**=anon
23                 /images/**=anon
24                 /**=authc
25             </value>
26         </property>
27     </bean>
28 
29     <!-- 配置authc过滤器(用户名和密码不使用默认配置username,password) -->
30     <bean id="authc" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
31         <property name="usernameParam" value="name"/>
32         <property name="passwordParam" value="pwd"/>
33     </bean>

  登录页面的改变:

1 <form action="login" method="post">
2 <!--     username:<input type="text" name="username"><br/>
3     password:<input type="password" name="password"><br/> -->
4     username:<input type="text" name="name"><br/>
5     password:<input type="password" name="pwd"><br/>
6     <input type="submit" value="login"> 
7 </form>

 7、授权

  (1)修改自定义Realm进行权限检查

  

  (2)在spring-mvc的配置文件中,添加AOP代理,并且添加异常处理

  

1     <!-- 开启AOP代理 -->
2     <aop:config proxy-target-class="true"></aop:config>
3     <!-- 开启Shiro注解支持 -->
4     <bean
5         class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
6         <property name="securityManager" ref="securityManager" />
7     </bean>

  在controller的处理方法中,添加权限检测的注解

  

  在jsp页面中,添加按钮权限检测,首先需要导入shiro的标签库

  

  在需要检查权限的地方,使用shiro标签

  

 8、缓存

  每次检查权限都会到数据库中获取权限,这样效率很低。可以通过设置缓存来解决该问题。Shiro可以和ehcache或者redis集成。这里使用ehcache来缓存数据。

  (1)将ehcache,jar导入系统。

  (2)shiro默认集成了一个ehcache的配置文件。也可以自己添加一个进行配置,放入resources下。

  ehcache.xml:

 1 <ehcache>
 2     <diskStore path="java.io.tmpdir/shiro-ehcache"/>
 3     <defaultCache
 4             maxElementsInMemory="10000"
 5             eternal="false"
 6             timeToIdleSeconds="120"
 7             timeToLiveSeconds="120"
 8             overflowToDisk="false"
 9             diskPersistent="false"
10             diskExpiryThreadIntervalSeconds="120"
11             />
12 </ehcache>

  (3)在applicationContext-shiro.xml中,添加cacheManager的配置

 1     <!-- 配置securityManager -->
 2     <bean id="securityManager"
 3         class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
 4         <property name="realm" ref="userRealm" />
 5         <property name="cacheManager" ref="cacheManager"></property>
 6     </bean>
 7     <!-- 配置缓存管理器 -->
 8     <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
 9         <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"></property>
10     </bean>

  (4)如果在运行过程中,主体的权限发生了改变,那么应该从spring容器中调用realm中的清理缓存方法,进行清理。

  UserRealm.java中添加清理缓存方法

1     //清理缓存方法
2     protected void clearCache() {
3         Subject subject = SecurityUtils.getSubject();
4         super.clearCache(subject.getPrincipals());
5     }

9、会话管理

 1     <!-- 配置securityManager -->
 2     <bean id="securityManager"
 3         class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
 4         <property name="realm" ref="userRealm" />
 5         <property name="cacheManager" ref="cacheManager"/>
 6         <property name="sessionManager" ref="sessionManager"/>
 7     </bean>
 8     <!-- 配置缓存管理器 -->
 9     <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
10         <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"></property>
11     </bean>
12     
13     <!-- 配置会话管理器 -->
14     <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
15         <!-- 失效时间单位是毫秒 -->
16         <property name="globalSessionTimeout" value="300000"/>
17         <!-- 删除无效session -->
18         <property name="deleteInvalidSessions" value="true"/>
19     </bean>

10、记住我

  (1)将用户类实现序列化接口,该类的引用类也必须实现序列化接口

  (2)设置登录时表单中“记住我”的域名

1     <!-- 配置authc过滤器(用户名和密码不使用默认配置username,password) -->
2     <bean id="authc" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
3         <property name="usernameParam" value="name"/>
4         <property name="passwordParam" value="pwd"/>
5         <property name="rememberMeParam" value="rememberMe"/>
6     </bean>

  (3)设置“记住我”管理器

 1     <!-- 配置securityManager -->
 2     <bean id="securityManager"
 3         class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
 4         <property name="realm" ref="userRealm" />
 5         <property name="cacheManager" ref="cacheManager"/>
 6         <property name="sessionManager" ref="sessionManager"/>
 7         <property name="rememberMeManager" ref="rememberMeManager"/>
 8     </bean>
 9     <!-- 配置缓存管理器 -->
10     <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
11         <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"></property>
12     </bean>
13     
14     <!-- 配置会话管理器 -->
15     <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
16         <!-- 失效时间单位是毫秒 -->
17         <property name="globalSessionTimeout" value="300000"/>
18         <!-- 删除无效session -->
19         <property name="deleteInvalidSessions" value="true"/>
20     </bean>
21     <!-- 记住我配置 -->
22     <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
23         <property name="cookie" ref="rememberMeCookie"></property>
24     </bean>
25     <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
26         <!-- 设置cookie存活时间    保存7天 -->
27         <property name="maxAge" value="604800"/>
28         <!-- 设置cookie的名称 -->
29         <property name="name" value="rememberMe"/>
30     </bean>
31     <!-- 记住我配置结束 -->

  (4)在过滤器链中配置哪些资源通过记住我就可以再次访问

 1         <!-- 配置shiro的过滤器链
 2             logout默认退出后跳转到根路径下,可以重新指定
 3          -->
 4         <property name="filterChainDefinitions">
 5             <value>
 6                 <!-- anon表示匿名 -->
 7                 /toLogin=anon
 8                 /login=authc
 9                 /logout=logout
10                 /js/**=anon
11                 /css/**=anon
12                 /images/**=anon
13                 /easyui/**=anon
14  /index=user
15                 /**=authc
16             </value>
17         </property>

  (5)jsp页面设置

1 <form action="login" method="post">
2 <!--     username:<input type="text" name="username"><br/>
3     password:<input type="password" name="password"><br/> -->
4     username:<input type="text" name="name"><br/>
5     password:<input type="password" name="pwd"><br/>
6     <input type="checkbox" name="rememberMe">记住我<br/>
7     <input type="submit" value="login"> 
8 </form>
原文地址:https://www.cnblogs.com/116970u/p/10956674.html