安全框架Shiro入门

Shiro简介

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

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

  • 认证java

  • 受权web

  • 会话管理spring

  • 加密数据库

引入jar包和配置web.xml

  • 引入Shiro对应的jar包,下面给出Mavenapache

    <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:框架提供的接口,表明当前用户对象app

  • SecurityManager:框架提供的接口,表明安全管理器对象

  • Realm:能够开发人员编写(即认证和受权方法)

  1. 咱们首先将登陆方法按照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;
        }
    
    }
  2. 而后编写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;
        }
    
    }
  3. 到上面之后编码工做就完成了,剩下的就是进行配置了,首先将编写的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>
  4. 配置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>
  5. 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>
相关文章
相关标签/搜索