您的位置:首页 > 其它

shiro实际开发整理

2017-12-29 10:52 162 查看

1.1         shiro介绍

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

三个核心组件:Subject, SecurityManager 和 Realms.

1、Subject

即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

2、SecurityManager

它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

3、Realm

Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

 

1.2         Shiro 体系结构



Authentication:身份认证/登录,验证用户是不是拥有相应的身份;

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用

户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用

户对某个资源是否具有某个权限;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信

息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的;

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web 支持,可以非常容易的集成到 Web 环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以

提高效率;

Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能

把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录

了。

记住一点,Shiro
不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过

相应的接口注入给 Shiro
即可。

 

1.3         Shiro运行原理



Application Code:应用程序代码,就是我们自己的编码,如果在程序中需要进行权限控制,需要调用Subject的API.

Subject:主体,代表的了当前用户。所有的Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager,可以将Subject当成一个门面,而真正执行者是SecurityManager.(可参考1.4.4登录Controller)

SecurityManage:安全管理器,所有与安全有关的操作都会与SecurityManager交互,并且它管理所有的Subject.

Realm:域 shiro是从Realm来获取安全数据(用户,角色,权限)。就是说 SecurityManager要验证用户身份, 那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法(可参考1.4.4认证);也需要从 Realm 得到用户相应的角色/权限进行验证用户是否能进行操作(可参考1.4.4授权);可以把 Realm 看成 DataSource,即安全数据源

 

从数据库中查询出的权限或角色与权限控制(权限控制方式可参考1.6)相匹配时通过验证

 

 

1.4     Shiro与spring集成

在企业开发中,使用spring集成shiro方案是常见的做法。

1.4.1maven依赖

 

<shiro.version>1.2.3</shiro.version>

 
<!-- shiro -->
<dependency>

    <groupId>org.apache.shiro</groupId>

    <artifactId>shiro-all</artifactId>

    <version>${shiro.version}</version>

</dependency>

 

1.4.2  在web.xml文件中配置

Shiro 提供了与 Web 集成的支持,其通过一个 ShiroFilter 入口来拦截需要安全控制的 URL,

然后进行相应的控制, ShiroFilter 类似于如 Strut2/SpringMVC 这种 web 框架的前端控制器,

其是安全控制的入口点,其负责读取配置(如 ini 配置文件),然后判断 URL 是否需要登

录/权限等工作。

 

<filter>
         <filter-name>shiroFilter</filter-name>
         <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
         <filter-name>shiroFilter</filter-name>
         <url-pattern>/*</url-pattern>
</filter-mapping>

Xml配置基础权限,不进行ini单独配置    以下为加载xml

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:spring-mybatis.xml,classpath:spring-shiro.xml</param-value>
</context-param>


 

DelegatingFilterProxy作用是自动到 spring 容器查找名字为 shiroFilter(filter-name)的 bean

并把所有 Filter 的操作委托给它

1.4.3  在spring-shiro.xml文件中配置

<bean
16ca8
id="shiroFilter"class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"
>

     <!--注入安全管理器-->

     <propertyname="securityManager"ref="securityManager"/>

     <!--  privateString loginUrl; 当后边配置url,需要当前用户认证通过后才可以访问;如果用户没有登陆,跳转登陆页面

           private String successUrl; 认证通过,默认跳转页面,建议不配置,shiro认证成功自动到上一个请求路径

           private String unauthorizedUrl; 未经授权-->

     <propertyname="loginUrl"value="/index.jsp"/>

     <propertyname="unauthorizedUrl"value="/unauthorized.jsp"></property>

     <!-- 注入过滤器链:配置系统中url请求拦截规则  注意:配置url拦截规则有顺序

       authc:过滤器工厂产生过滤器之一

    /**:所有请求

       当系统发送某url要求当前用户必须认证通过后才能访问

      anon:匿名过滤器:访问url不需要当前用户认证,没有权限可以访问

      perms:权限过滤器:访问url需要当前用户具有某个权限才可以访问

-->

     <propertyname="filterChainDefinitions">

         <value>

             /index.jsp = anon  

             /datejs/** = anon

             /lib/** = anon

             /static/** = anon   
静态资源需要放过,一些登录等不需权限也可访问的资源
             /login = anon

             /loginp =anon

             /welcome.html =anon

             /** =  authc

         </value>

     </property>

 </bean>

 

 

<!--配置安全管理器对象 -->
<beanid="securityManager"class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

    <propertyname="realm"ref="userRealm"></property>
</bean>

 

!--
配置realm对象 -->
<beanid="userRealm"class="com.cn.xxx.shiro.UserRealm"></bean>   

<!-- spring提供配置shiro注解扫描

    在servie层方法上使用shiro注解,运行时期此方法所在类产生代理对象

    AutoProxy:自动代理,根据请求自动选择代理技术

        jdk动态代理:基于接口

        cglib动态代理:基于Class

    注意:强制使用cglib动态代理

 -->
<beanclass="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">

    <propertyname="proxyTargetClass"value="true"></property>
</bean>
<!-- 配置shiro的切面:(切点+通知/增强)  增强:验证当前用户是否有权限 -->
<beanclass="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"></bean>

 

1.4.4自定义realm实现授权与认证

 

自定义realm一般是继承AuthorizingRealm,因为它提供了认证与授权功能

 

认证操作

@Override
protected AuthenticationInfodoGetAuthenticationInfo(AuthenticationToken authenticationToken)throwsAuthenticationException
{

    System.out.println("开始认证");

    UsernamePasswordTokenusernamePasswordToken = (UsernamePasswordToken) authenticationToken;

    //页面输入的用户名

    //根据用户名查询数据库中真实密码

    String username = usernamePasswordToken.getUsername();

    User user = iUserService.queryAccountByName(username);

    if(user==null){

        //用户名输出错误

        return null; //当次方法中返回null,shiro会抛出异常 :未知账户异常

    }

    //比对密码工作交给shiro框架

    //p1:主角  p2:令牌/真实密码  p3:当前realm名称

    AuthenticationInfo info = newSimpleAuthenticationInfo(user,user.getPwd(),this.getName());

    return info;

}

授权操作

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    List<Permission> permissionList = new ArrayList<>();
    List<Role> roleList = new ArrayList<>();
    System.out.println("开始授权");
    //返回简单授权信息:包含当前用户有的权限点;角色
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

    //如果系统内置账户:管理员账户,有所有的权限以及角色
    Subject subject = SecurityUtils.getSubject();
    User user = (User) subject.getPrincipal();
    if("admin".equalsIgnoreCase(user.getAccount())){
        permissionList = permissionService.queryPermissionList();
    }else{

        //根据用户ID进行查询
        roleList = iUserService.queryRoleByID(user.getId());
        roleList.removeAll(Collections.singleton(null));
        if (!roleList.isEmpty()){
            List<Role> list = roleService.queryPermissionByRoleId(roleList.get(0).getRoleId());
            permissionList = list.get(0).getPermissionList();
        }
    }

    if(permissionList != null && !permissionList.isEmpty()){
        //添加用户权限
        for (Permission permission : permissionList) {
            if (permission.getPermissionUrl() == null || permission.getPermissionUrl().trim() == ""){
                continue;
            }
            info.addStringPermission(permission.getPermissionUrl());
        }
    }

    if (roleList != null && !roleList.isEmpty()){
        //添加用户角色
        for (Role role : roleList) {
            info.addRole(role.getRoleName());
        }
    }

    return info;             
}


 

 

登录Controller中调用: 通过认证的令牌,与登录的密码和账户进行匹配,如果登录失败,user为null

 


1.5    Shiro整合ehcache

1.       导入ehcache的maven依赖

<!--shiro缓存 ehcache-->
<dependency>

    <groupId>net.sf.ehcache</groupId>

    <artifactId>ehcache-core</artifactId>

    <version>2.6.11</version>
</dependency>

 

2.       在src/main/resource下提供ehcache的配置文件shiro-ehcache.xml

<ehcachename="shirocache">

       <!-- diskStore:磁盘存储目录 -->

    <diskStorepath="/opt/tomcat/shiroCache/ehcache"/>

    <!-- 缓存策略:

       maxElementsInMemory:内存中存储对象个数

       eternal:缓存数据是否永久有效

       timeToIdleSeconds:内存 中对象最大空闲时间

       timeToLiveSeconds:内存 中对象最大存活时间

       maxElementsOnDisk:磁盘中存储对象个数

       diskExpiryThreadIntervalSeconds:清除缓存数据线程执行周期单位:秒

       memoryStoreEvictionPolicy:清理缓存中对象策略  LRU:最近最少使用  FIFO:先进先出

        -->

    <defaultCache

            maxElementsInMemory="10000"

            eternal="false"

            timeToIdleSeconds="120"

            timeToLiveSeconds="120"

            maxElementsOnDisk="10000000"

            diskExpiryThreadIntervalSeconds="120"

            memoryStoreEvictionPolicy="LRU"
>

        <persistencestrategy="localTempSwap"/>

    </defaultCache>
 

</ehcache>

 

3.      将ehcache缓存管理交给spring管理

 

<!--配置ehcache缓存管理器对象 -->
<beanid="cacheManager"class="org.apache.shiro.cache.ehcache.EhCacheManager">

    <!-- 注入ehcache配置文件:配置缓存策略 -->

    <propertyname="cacheManagerConfigFile"value="classpath:shiro-ehcache.xml"></property>
</bean>

 

4.       注入缓存管理对象

<!--配置安全管理器对象 -->
<beanid="securityManager"class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

    <propertyname="realm"ref="userRealm"></property>

    <!-- 注入缓存管理对象 -->

    <propertyname="cacheManager"ref="cacheManager"></property>
</bean>

 

5.       在realm中引入缓存管理 因为使用的是默认配置,此处省略

<!--
配置realm对象 -->
<beanid="userRealm"class="com.cn.xxx.shiro.UserRealm">xxx</bean>
 

1.6         Shiro总结

Shiro为程序共提供了四种权限控制方式

1.6.1             第一种 url级别权限控制



ShiroFilter具有上面10个Filter校验功能!!!!

l  anon
不需要认证和登陆可以访问

l  authc
必须认证后才能访问

l  perms
必须具有某个权限才能访问

l  roles 
必须具有某个角色才能访问

l  port 请求必须符合端口才能访问

l  rest 限制HTTP请求方式 post、get

l  ssl 必须用https才能访问

l  user 必须存在用户才能访问

存在用户(cookie)和认证(session)不一样

logout 必须session里面没有这个用户才能访问



<propertyname="filterChainDefinitions">   <value>       /index.jsp
= anon        /datejs/** = anon        /lib/** = anon        /static/** = anon        /login = anon        /loginp =anon        /welcome.html =anon        /** =  authc   </value></property>

1.6.2             第二种 页面标签权限控制

        

 


例如:

<shiro:hasPermission name="user">
   <div class="menu_dropdown bk_2">
      <dl id="menu-article">
         <dt><i class="Hui-iconfont"></i>用户管理<i class="Hui-iconfont menu_dropdown-arrow"></i></dt>
         <dd>
            <ul><shiro:hasPermission name="/user/manage">
               <li><a data-href="${ctx}/user/manage" data-title="查看用户信息" href="javascript:void(0)">用户信息</a></li>
               </shiro:hasPermission>
               <shiro:hasPermission name="/user/roleManage">
               <li><a data-href="${ctx}/user/roleManage" data-title="角色管理" href="javascript:void(0)">角色管理</a></li>
               </shiro:hasPermission>
               <shiro:hasPermission name="/user/permissionManage">
                  <li><a data-href="${ctx}/user/permissionManage" data-title="权限管理" href="javascript:void(0)">权限管理</a></li>
               </shiro:hasPermission>
            </ul>
         </dd>
      </dl>
   </div>
</shiro:hasPermission>


在这里我是以路径作为权限名,也可以使用其他

 

注:每一次遇到权限标签就会触发授权,到数据库中查询。如果权限标签比较多,请使用缓存,提高效率

 

 

以下两种权限控制未测试

1.6.3             第三种 注解方式实现权限控制

Shiro为我们提供了5中注解

         @RequiresAuthentication:验证用户是否登录,等同于方法subject.isAuthenticated()结果为true时。

         @RequiresUser:验证用户是否被记忆,user有两种含义:一种是成功登录的([b]subject.isAuthenticated()结果为true);[/b] 另外一种是被记忆的(subject.isRemembered()结果为真)。

         @[b]RequiresGuest:验证用户是否是一个guest的请求,与@RequiresUser完全相反。不需要经过认证[/b]

         @RequiresRoles:例如:@RequiresRoles(“RoleName”)如果subject中有RoleName角色才可以访问方法。如果没有这个权限则抛出异常AuthorizationException

[b][b]         @[b]RequiresPermissions:[/b][/b][/b]例如:@RequiresPermissions(“permissionName1”,“permissionName2”)要求subject中必须同时含有permissionName1和permissionName2的权限才能执行方法,否则抛出异常AuthorizationException

在spring-mvc.xml配置文件中配置(要写在最先加载的xml中)

<!--权限注解开启-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" />
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>

lifecycleBeanPostProcessor和securityManager是在shiro配置文件中定义好的:

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>

<!-- Shiro安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="jdbcRealm"></property>
<property name="cacheManager" ref="cacheManager"></property>
</bean>


a)    业务层注解权限控制

注意事项1

因为我们是在实现类上去使用的注解,需要我们指定代码方式



注意事项2

在service层因为权限出现问题,那么会产生异常,我们需要在表现层进行处理

在抛出异常上,可采用springMVC的统一异常处理:点击打开链接

1.6.4             第四种 代码级别权限控制

Subject subject = SecurityUtils.getSubject();


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  shiro 权限 开发