shiro基本配置和使用

这里讲shiro整合spring 实现登录验证 和权限拦截

首先pom文件添加依赖

<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.3.2</version>
</dependency>

<!-- spring整合shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>


<!-- ehcache-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
</dependency>

shiro要结合ehcache这个缓存框架 可以实现一些功能 比如限制用户登录密码错误次数 然后限制多久时间内,限制登录

接下来就来就是配置文件 首先web.xml
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>DelegatingFilterProxy</param-name>
<param-value>true</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

这是配置一个shiro过滤器 将所有的请求都交给shiro处理 至于spring的配置我这里就不写了 和正常的配置一样

然后ehcache缓存框架需要一个配置文件 我这里贴出来 文件名就叫 ehcache.xml
 1 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">  
 2 
 3        <diskStore path="${webapp.root}"/>  
 4      
 5     <defaultCache
 6             maxElementsInMemory="10000"
 7             maxElementsOnDisk="0"
 8             eternal="true"
 9             overflowToDisk="true"
10             diskPersistent="false"
11             timeToIdleSeconds="0"
12             timeToLiveSeconds="0"
13             diskSpoolBufferSizeMB="50"
14             diskExpiryThreadIntervalSeconds="120"
15             memoryStoreEvictionPolicy="LFU"
16     />
17    </ehcache>
接下来就是spring整合shiro的配置文件
 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.xsd">
 5 
 6 
 7 <!-- 配置ehCache缓存支持-->
 8 <bean name="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
 9 <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"></property>
10 </bean>
11 
12 
13     <!-- 自定义Realm-->
14 <bean name="userRealm" class="com.newer.web.shiro.MyRealm" >
15 
16     <!--注入加密算法类 -->
17     <property name="credentialsMatcher">
18 
19     <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
20         <!--加密算法名 -->
21         <property name="hashAlgorithmName" value="MD5"/>
22         <!--加密次数 -->
23         <property name="hashIterations" value="6"/>
24     </bean>
25 
26     </property>
27 
28 
29 </bean>
30 
31 
32 <!-- shiro安全管理器-->
33 <bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
34 <property name="cacheManager" ref="cacheManager"></property>
35 <property name="realm" ref="userRealm"></property>
36 </bean>
37 
38 
39 <!-- 管理shiro bean的生命周期 -->
40 <bean name="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>
41 
42 
47 
48     <!--shiro核心过滤器配置-->
49     <bean name="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
50         <property name="securityManager" ref="securityManager"/>
51         <property name="loginUrl" value="/login.jsp"></property> <!-- 没有认证  跳转的登录连接 -->
52         <property name="unauthorizedUrl" value="/unauthorized.jsp"></property> <!-- 没有访问权限 跳转的页面 -->

82 <!--这里使用 从数据库查询出来要拦截的url集合 注入到这个对象中 实现拦截 --> 83 <property name="filterChainDefinitionMap" ref="map"/> 86 </bean> 87 88 89 <!--实例工厂方法 将执行shiroFilterUtils类的build的方法 --> 90 <bean name="map" factory-bean="shiroFilterUtils" factory-method="build"/> 91 92 <!--这个类将从数据库中查询要拦截的url信息--> 93 <bean name="shiroFilterUtils" class="com.newer.util.ShiroFilterUtils"/> 97 </beans>

 

别的配置不说  shiro核心过滤器bean的 name的值 一定要与web.xml里面配置的shiro过滤器的名字一样 否则会报错

然后我这里是使用实例工厂方法  将一个存有要拦截的url的map集合 注入到ShiroFilterFactoryBean 中的filterChainDefinitionMap属性

这样当我们的请求经过shiro过滤器时  会根据我们配置的要拦截的url和使用相应的拦截器 对请求进行处理  

现在把我这个工具类贴出来

/**
 * 这个类会在 spring容器初始化bean时  从数据库将要拦截的url
 * 查询出来 封装成集合  注入到ShiroFilterFactoryBean类的filterChainDefinitions属性中
 * 这样实现对需要相应权限才能访问的url进行拦截 并由shiro验证是否具有相应权限
 */

public class ShiroFilterUtils {

  public Map<String,String> build(){

   

     Map<String,String> map= new LinkedHashMap<String, String>();

//添加固定要拦截的url map.put("/user/login.do","anon"); map.put("/login.jsp","anon"); map.put("/**","authc"); return map; } }

这里讲一下  url和拦截器的语法

url使用的是 Ant风格

 ? 匹配任何单字符

 * 匹配0或者任意数量的字符

** 匹配0或者更多的目录

拦截器常用有:
anon 匿名的 不需要认证 也可以访问
authc 必须认证才可以访问 没有认证会跳转登录链接
user 登录之后启用了记住我功能 就可以访问

roles 例如 roles[管理员] 表示必须具有管理员权限才可操作 如果是roles[管理员,经理] 表示要具有管理员和经理权限才可以访问
------------------------------------------
shiro会将请求的url按照顺序和map集合中的所有url匹配 如果匹配到了 不会再匹配后续url 所以要注意 map集合中要拦截的url的顺序
我这里就没有将要拦截的url 从数据库中查出 如果需要从数据集中查出 然后将要拦截的url作为key 要使用的拦截器作为value 存入这个map集合即可


权限管理就这么多 接下来说登录认证 贴出我的controller
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/login")
    public String login(String userName, String userPassword, ModelMap map){

        //得到当前 Subject
        Subject currentSubject= SecurityUtils.getSubject();

            //创建用户名密码 token
            UsernamePasswordToken token= new UsernamePasswordToken(userName,userPassword);

            //记住当前用户 关掉浏览器 重开也能访问 不是authc 拦截器的url
            token.setRememberMe(true);

            try {
                //执行登录方法
            currentSubject.login(token);

            }catch (IncorrectCredentialsException ie){
                //将抛出的登录异常 存储 然后返回登录页面 显示给用户
                map.put("loginMessage","用户名或密码错误!!!");
                return "forward:/login.jsp";

            }catch (AuthenticationException ae){ //所有异常的父类
              map.put("loginMessage","未知错误 请联系管理员");
              return "forward:/login.jsp";
            }


        return "success";
    }


    @RequestMapping("/logout")
    public String logout(){

        //得到当前 Subject
        Subject currentSubject= SecurityUtils.getSubject();

        //注销当前 Subject
        currentSubject.logout();

      return "redirect:/login.jsp";

    }






   //这里面没有去写注册方法了  注册的时候 要将密码 通过这样加密后存入到数据库
    public static void main(String[] args) {

        //生成MD5加密的密码  参1:加密方式 ,参2:未加密的密码  参3:盐值 使用当前用户名  参4:加密次数
        Object str= new SimpleHash("MD5","123456","zhangsan",6);

        System.out.println("str = " + str);
    }


}

 


当执行
login()方法时 会调用我们在shiro配置文件中配置的自定义Realm类 login方法出现错误 会抛出异常 我们用catch可以捕获对应异常

接下来贴出我的
Realm类
@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Autowired
    private AuthorityService authorityService;



    @Override    //认证方法
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        //将token强转成 用户密码token
        UsernamePasswordToken token=(UsernamePasswordToken)authenticationToken;

        //根据传入的用户名 查询数据库  返回用户对象
        User user=userService.queryByUserName(token.getUsername());

        //没有查到用户 直接抛出异常
        if(user==null){

            throw  new IncorrectCredentialsException();

        }

        //根据当前用户名 生成盐值  用于结合加密算法对密码进行加密
        ByteSource salt=ByteSource.Util.bytes(token.getUsername());

        //将用户名和密码 交由shiro认证 如果出错会抛出对应异常   参数1:用户名 参数2:用户密码 参3:盐值 参数4:当前Realm的名字
        return new SimpleAuthenticationInfo(user.getUserName(),user.getUserPassword(),salt,this.getName());

    }



    @Override   //授权方法
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //获得用户名
        String userName= (String) principalCollection.getPrimaryPrincipal();

        //根据用户名 查询当前用户 拥有的权限
        Set<String>  roles=authorityService.queryByUserName(userName);

        //将当前权限集合 返回交给shiro处理 权限认证
        return new  SimpleAuthorizationInfo(roles);
    }





}

 

第二个授权方法  就是当请求需要对应权限的拦截器的url时   shiro会调用这个方法  然后我们根据当前用户名 查询出当前用户所拥有的权限

然后交给shiro 由他去比对当前用户是否拥有可以访问的资格 如果没有就会跳转到我们在配置文件中 shiro过滤器配置的unauthorizedUrl属性的值去

 

shiro的基本用法就这些  网上看了很多教程 都是各不相同  不像别的框架  教程都差不多  暂时总结到这里 后续有新的用法 再来加上吧 




 

 

 

 


posted @ 2019-06-01 11:18  沙漠里的橘子皮  阅读(6901)  评论(0编辑  收藏  举报