安全框架Shiro入门

Shiro简介

Apache Shiro是Java的一个安全框架,官网为shiro.apache.org,主要场景为控制登陆,判断用户是否有访问某个功能的权限等等。

Shiro的核心功能(入门知识,只介绍前两个)

  • 认证
  • 授权
  • 会话管理
  • 加密

引入jar包和配置web.xml

引入Shiro对应的jar包,下面给出Maven
 <dependency>     
     <groupId>org.apache.shiro</groupId>     
     <artifactId>shiro-all</artifactId>     
     <version>1.2.2</version> 
  </dependency>
在web.xml中配置spring框架提供的用于整合shiro框架的过滤器
     <!-- 配置shiro过滤器 --> 
     <filter>     
          <filter-name>shiroFilter</filter-name>    // 需要在spring的配置文件中创建一个bean(shiroFilter)     
          <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>    
      </filter> 
      <filter-mapping>    
            <filter-name>shiroFilter</filter-name>     
            <url-pattern>/*</url-pattern> 
      </filter-mapping>

下面我们将要进行Shiro的认证功能和授权功能的实现,代码比较多。

登录方法的实现

Shiro认证的流程

  • Application Code:应用程序代码, 即登录方法(登录方法不是直接查询数据库,而是调用Shiro框架提供的接口来实现)
  • Subject:框架提供的接口,代表当前用户对象
  • SecurityManager:框架提供的接口,代表安全管理器对象
  • Realm:可以开发人员编写(即认证和授权方法)
我们首先将登录方法按照Shiro指定的方式进行改进
  public String login() {     
      // 获取验证码     
      String validateCode = (String) ServletActionContext.getRequest().getSession().getAttribute("key");     
      // 判断验证码     
      if (StringUtils.isNotBlank(checkcode) && checkcode.equals(validateCode)) {           
          // 获取getSubject对象,Shiro中代表当前用户对象         
          Subject subject = SecurityUtils.getSubject();          
          // 令牌 传递进去前台接受的账号和密码         
          AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),      
          MD5Utils.md5(model.getPassword()));// 创建用户名密码令牌对象         
          try {             
              subject.login(token); // 调用内置的登录方法来实现检验 如果登陆错误就会抛出异常,返回登录页面   
          } catch (Exception e) {             
              e.printStackTrace();             
              return LOGIN;         
           }         
           User user = (User) subject.getPrincipal();   // 登录成功后可以从subject取得登录对象   
           ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);      
           return HOME;      
           
           } else {         
               this.addActionError("输入验证码错误");         
               return LOGIN;     
           }  
  }
然后编写Realm继承AuthorizingRealm ,即编写具体的认证和授权方法
     public class BOSRealm extends AuthorizingRealm {    
      @Autowired     
      private IUserDao userDao      
      // 授权方法    
       protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {         
            // 可以在这里将用户所属的权限查询出来,然后遍历赋值给info对象,这样就可以实现了授权        
             // 判断访问路径或者方法有没有权限的时候就是根据info中的数据来判断         
             info.addStringPermission("staff-list");         
             return info;     
       }     
       // 认证方法(登陆方法)     
       protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {         
             System.out.println("认证...");         
             UsernamePasswordToken passwordToken = (UsernamePasswordToken) arg0;   // 对象转换  
             String username = passwordToken.getUsername();   // 获得username         
             User user = userDao.findByUsername(username);    // 通过username从数据库中获取到User对象         
             if (user == null) {             
             return null;         
             }         
             // 内置验证方法 (数据库中获取的对象,对象的密码, this.getName())         
             AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());           
             return authenticationInfo;     
         }  
    }
到上面以后编码工作就完成了,剩下的就是进行配置了,首先将编写的Realm注入到安全管理器,整合的是Spring,所以下面的配置都是在Spring配置文件中。
 <!-- 注册realm --> 
 <bean id="bosRealm" class="lyh.bos.realm.BOSRealm"></bean>  
 
 <!-- 注册安全管理器对象 --> 
 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">     
     <property name="realm" ref="bosRealm"/> 
 </bean>
配置ShiroFilterFactoryBean,同时还可以配置一下URL拦截规则,注意这里的id要和web.xml<filter-name>shiroFilter</filter-name>相同
 <!-- shiro 配置 --> 
 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  <!-- 此处为web.xml配置的拦截器 -->     
     <!-- 注入安全管理器对象 -->     
     <property name="securityManager" ref="securityManager"/>        
     <!-- 注入相关页面访问URL -->     
     <property name="loginUrl" value="/login.jsp"/>          <!-- 登录页面 -->     
     <property name="successUrl" value="/index.jsp"/>   <!-- 登录成功的主页 -->     
     <property name="unauthorizedUrl" value="/unauthorized.jsp"/>   <!-- 权限不足转向的错误页面 --> 
     <property name="unauthorizedUrl" value="/unauthorized.jsp"/>      
     <!--注入URL拦截规则, -->
     <!-- anon 都可以访问                       
                 perms["staff-list"] 是否有staff-list权限                     
                 authc 登录才可以访问 -->     
     <property name="filterChainDefinitions">           
           <value>             
               /css/** = anon             
               /admin/logout = logout    
               <!-- 注销,访问这个路径,自动注销不需要自己编写方法 -->             
               /images/** = anon             
               /validatecode.jsp* = anon             
               /login.jsp = anon             
               /userAction_login.action = anon             
               /page_base_staff.action = perms["staff-list"]   <!-- 表示page_base_staff.action路径需要有staff-list权限才可访问 -->             
               /* = authc             
           </value>     
      </property> 
  </bean>
Shiro还提供了使用注解控制权限的方法,开启方式如下,同时,使用的注解权限还需要配置全局异常,用来捕获当权限不足抛出异常时转向的页面,这里使用的是SpringMVC,开启方式@RequiresPermissions("staff-list")
     <!-- 开启注解配置权限 --> 
     <bean id="defaultAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">     
          <!-- 必须使用cglib方式为       Action对象创建代理对象 -->     
          <property name="proxyTargetClass" value="true"/> 
      </bean> 
      
     <!-- 配置shiro框架提供的切面类,用于创建代理对象 --> 
     <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/> 
 
 
 
      // 配置全局异常处理器     
      <!-- 需要进行权限控制的页面访问 --> 
      <global-results>     <
           result name="login">/login.jsp</result>     
           <result name="unauthorized">/unauthorized.jsp</result> 
       </global-results>  
       <!-- 全局异常处理 --> 
       <global-exception-mappings>     
            <exception-mapping result="unauthorized" exception="org.apache.shiro.authz.UnauthorizedException"></exception-mapping> 
       </global-exception-mappings>

Shiro提供的控制权限的方式

  • URL权限拦截控制
  • 方法注解权限控制
  • 页面标签权限控制(当有对应的权限就显示对应的页面元素,没有权限则不显示), 需要在对应的页面引入Shiro的标签库 <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>,可以用在HTMl也可以用在JS中。
  • 代码级别权限控制(在方法内添加代码)

Shiro整合ehcache缓存权限数据

如果访问一个页面就执行一次授权,就会访问数据库,浪费资源,所以我们可以使用ehcache来进行缓存权限,只要登录时进行一次授权,后面无需再次授权,直接使用缓存。

shiro自动整合ehcache,只需要简单配置就能使用。

在根目录下建立ehcache.xml
 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> 
 <diskStore path="java.io.tmpdir"/> 
     <defaultCache         
         maxElementsInMemory="10000"             
         eternal="false"         
         timeToIdleSeconds="600"         
         timeToLiveSeconds="600"         
         overflowToDisk="true"         
         maxElementsOnDisk="10000000"         
         diskPersistent="false"         
         diskExpiryThreadIntervalSeconds="120"         
         memoryStoreEvictionPolicy="LRU"         
         />  
         <!--      
         内存中最多可以存储多少个数据      
         是否永久有效     
         空闲时间     
         存活时间     
         内存空间不够是否存储到磁盘     
         磁盘最大存储个数     
         服务器重启,磁盘数据是否需要     
         线程     
         淘汰策略(最近最少使用)    -->   
   </ehcache>
  • 在spring配置文件中配置缓存管理器对象,并注入给安全管理器对象
        <!-- 注册ehcache -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
    </bean>
  • 将ehcache注入到shiro的配置管理器,shiro会自动使用缓存管理,在原来的管理器中添加<property name="cacheManager" ref="cacheManager"/> 一条语句即可。
        <!-- 注册安全管理器对象 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="bosRealm"/>
        <!-- 将ehcache注入shiro -->
        <property name="cacheManager" ref="cacheManager"/>
    </bean>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一“技”之长

Java开发GUI之列表 原

    awt包中的List控件可以创建一个选择列表,此列表可以支持单选,也可以支持多选。

1152
来自专栏架构之路

SpringMVC + Mybatis bug调试 SQL正确,查数据库却返回NULL

今天碰到个bug,有点意思 背景是SpringMVC + Mybatis的一个项目,mapper文件里写了一条sql 大概相当于 select a from t...

3447
来自专栏Ceph对象存储方案

源码走读rgw内置civetweb的参数初始化过程

1. 初始化civetweb时刻的参数传递 src/civetweb/civetweb.h /* Start web server. Paramete...

3517
来自专栏技术博客

ExtJs四(ExtJs MVC登录窗口的调试)

继上一节中实现了验证码http://www.cnblogs.com/aehyok/archive/2013/04/19/3030212.html,现在我们可以进...

662
来自专栏大内老A

[WCF 4.0新特性] 默认终结点

很多WCF的初学者是从之前的Web服务上转移过来的,他们非常怀念.asmx Web服务无配置的服务寄宿方式。你只需要在定义Web服务的时候再表示服务操作的方法上...

1795
来自专栏程序员互动联盟

【android开发】Android HAL模块实现

1. HAL介绍 Android的HAL(Hardware Abstract Layer硬件抽象层)是为了保护一些硬件提供商的知识产权而提出的,是为了避开lin...

4607
来自专栏Java技术

Tomcat服务器顶层结构和启动过程

通过从部署的 1240 个 JVM 中得到的数据,我们能够确定出现了 862 个容器供应商,或者说是占到了运行环境的 70% 左右。这些容器的供应商分布如下:

682
来自专栏MasiMaro 的技术博文

PE文件详解二

本文转自小甲鱼的PE文件相关教程,原文传送门 咱接着往下讲解IMAGE_OPTIONAL_HEADER32 结构定义即各个属性的作用! 接着我们来谈谈 ...

883
来自专栏liulun

基于.net开发chrome核心浏览器【四】

一: 上周去北京出差,给国家电网的项目做架构方案,每天都很晚睡,客户那边的副总也这样拼命工作。 累的不行了,直接导致第四篇文章没有按时发出来。 二: 在这篇文章...

1979
来自专栏ImportSource

像Spring Boot那样创建一个你自己的Starter

如果你所在的公司要开发一个共享的lib,或者如果你想要为开源世界做点贡献,你也许想要开发你自己的自定义的自动配置类以及你自己的starter pom。这些自动配...

3249

扫码关注云+社区