zoukankan      html  css  js  c++  java
  • Shiro的基本介绍及理解

           最近,也在学习Shiro,项目中也有用到。更多可看官网http://shiro.apache.org/ 学习。同时也看了其他人写的一些博客,现把一些好的知识点总结归纳一下。

    一、Shrio简介

      Apache Shiro是Java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。而且,Shiro扩展也很容易,基本上要有的功能都有。

         Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。Shiro可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存等。这不就是我们想要的嘛,而且Shiro的API也是非常简单;其基本功能点如下图所示:

        

        

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

    Authorization授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

    Session Manager会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

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

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

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

    Concurrencyshiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

    Testing提供测试支持;

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

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

    记住一点,Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro即可。

    接下来我们分别从外部和内部来看看Shiro的架构,对于一个好的框架,从外部来看应该具有非常简单易于使用的API,且API契约明确;从内部来看的话,其应该有一个可扩展的架构,即非常容易插入用户自定义实现,因为任何框架都不能满足所有需求。

    首先,我们从外部来看Shiro吧,即从应用程序角度的来观察如何使用Shiro完成工作。如下图:

    可以看到:应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject;其每个API的含义:

    Subject主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

    SecurityManager安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

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

    也就是说对于我们而言,最简单的一个Shiro应用:

    1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;

    2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。

    从以上也可以看出,Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入。

    接下来我们来从Shiro内部来看下Shiro的架构,如下图所示:

     

    Subject主体,可以看到主体可以是任何可以与应用交互的“用户”;

    SecurityManager相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理。

    Authenticator认证器,负责主体认证的,这是一个扩展点,如果用户觉得Shiro默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;

    Authrizer授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;

    Realm可以有1个或多个Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;由用户提供;注意:Shiro不知道你的用户/权限存储在哪及以何种格式存储;所以我们一般在应用中都需要实现自己的Realm;

    SessionManager如果写过Servlet就应该知道Session的概念,Session呢需要有人去管理它的生命周期,这个组件就是SessionManager;而Shiro并不仅仅可以用在Web环境,也可以用在如普通的JavaSE环境、EJB等环境;所有呢,Shiro就抽象了一个自己的Session来管理主体与应用之间交互的数据;这样的话,比如我们在Web环境用,刚开始是一台Web服务器;接着又上了台EJB服务器;这时想把两台服务器的会话数据放到一个地方,这个时候就可以实现自己的分布式会话(如把数据放到Memcached服务器);

    SessionDAODAO大家都用过,数据访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,通过如JDBC写到数据库;比如想把Session放到Memcached中,可以实现自己的Memcached SessionDAO;另外SessionDAO中可以使用Cache进行缓存,以提高性能;

    CacheManager缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能

    Cryptography密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密的。

    以上,仅仅是Shiro框架的介绍,具体详细介绍及文档可看官网api    http://shiro.apache.org/reference.html

    下面以具体实例介绍加以理解:

    Shiro官网例子就很经典,很好让我们理解Shiro框架

    使用Shiro框架用户登录流程图:

    SecurityManager是Shiro的核心,我们首先要实例化SecurityManager,才能使用Shiro。任何框架使用管理大都从配置文件开始。Shiro也不例外

    1、加载配置文件

       src/main/resources/shiro.ini

     1 # =============================================================================
     2 # Tutorial INI configuration
     3 #
     4 # Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)
     5 # =============================================================================
     6 
     7 # -----------------------------------------------------------------------------
     8 # Users and their (optional) assigned roles
     9 # username = password, role1, role2, ..., roleN
    10 # -----------------------------------------------------------------------------
    11 [users]
    12 root = secret, admin
    13 guest = guest, guest
    14 presidentskroob = 12345, president
    15 darkhelmet = ludicrousspeed, darklord, schwartz
    16 lonestarr = vespa, goodguy, schwartz
    17 
    18 # -----------------------------------------------------------------------------
    19 # Roles with assigned permissions
    20 # roleName = perm1, perm2, ..., permN
    21 # -----------------------------------------------------------------------------
    22 [roles]
    23 admin = *
    24 schwartz = lightsaber:*
    25 goodguy = winnebago:drive:eagle5

    配置文件中有配置用户和角色信息,这些配置决定了外面登录用户是否有权限登录系统。

    2、实例化SecurityManager并注入内存中

    //加载配置文件
    Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
    //解析配置文件并实例化securityManager
    SecurityManager securityManager = factory.getInstance();
    //把securityManager放入内存中,注入securityManager
    SecurityUtils.setSecurityManager(securityManager);

    3、获取subject对象(可理解当前用户)

       Subject currentUser = SecurityUtils.getSubject();

    4、可以对获取的subject进行其他验证操作

         比如,可获取session,区别于httpSession,并不依赖http环境。默认的web项目,session为httpSession。但其使用和httpSession功能一样的。

        session中设置值:

        Session session = currentUser.getSession();

        session.setAttribute("someKey", "aValue");

        String value = (String) session.getAttribute("someKey");

        if (value.equals("aValue")) {

        log.info("Retrieved the correct value! [" + value + "]");

        }

       验证当前用户是否授权,是否有角色和权限登录。

       具体代码如下:

      src/main/java/Tutorial.java

      

     1 import org.apache.shiro.SecurityUtils;
     2 import org.apache.shiro.authc.*;
     3 import org.apache.shiro.config.IniSecurityManagerFactory;
     4 import org.apache.shiro.mgt.SecurityManager;
     5 import org.apache.shiro.session.Session;
     6 import org.apache.shiro.subject.Subject;
     7 import org.apache.shiro.util.Factory;
     8 import org.slf4j.Logger;
     9 import org.slf4j.LoggerFactory;
    10 
    11 public class Tutorial {
    12 
    13     private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);
    14 
    15     public static void main(String[] args) {
    16         log.info("My First Apache Shiro Application");
    17 
    18         Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
    19         SecurityManager securityManager = factory.getInstance();
    20         SecurityUtils.setSecurityManager(securityManager);
    21 
    22         // get the currently executing user:
    23         Subject currentUser = SecurityUtils.getSubject();
    24 
    25         // Do some stuff with a Session (no need for a web or EJB container!!!)
    26         Session session = currentUser.getSession();
    27         session.setAttribute("someKey", "aValue");
    28         String value = (String) session.getAttribute("someKey");
    29         if (value.equals("aValue")) {
    30             log.info("Retrieved the correct value! [" + value + "]");
    31         }
    32 
    33         // let's login the current user so we can check against roles and permissions:
    34         if (!currentUser.isAuthenticated()) {
    35             UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
    36             token.setRememberMe(true);
    37             try {
    38                 currentUser.login(token);
    39             } catch (UnknownAccountException uae) {
    40                 log.info("There is no user with username of " + token.getPrincipal());
    41             } catch (IncorrectCredentialsException ice) {
    42                 log.info("Password for account " + token.getPrincipal() + " was incorrect!");
    43             } catch (LockedAccountException lae) {
    44                 log.info("The account for username " + token.getPrincipal() + " is locked.  " +
    45                         "Please contact your administrator to unlock it.");
    46             }
    47             // ... catch more exceptions here (maybe custom ones specific to your application?
    48             catch (AuthenticationException ae) {
    49                 //unexpected condition?  error?
    50             }
    51         }
    52 
    53         //say who they are:
    54         //print their identifying principal (in this case, a username):
    55         log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
    56 
    57         //test a role:
    58         if (currentUser.hasRole("schwartz")) {
    59             log.info("May the Schwartz be with you!");
    60         } else {
    61             log.info("Hello, mere mortal.");
    62         }
    63 
    64         //test a typed permission (not instance-level)
    65         if (currentUser.isPermitted("lightsaber:weild")) {
    66             log.info("You may use a lightsaber ring.  Use it wisely.");
    67         } else {
    68             log.info("Sorry, lightsaber rings are for schwartz masters only.");
    69         }
    70 
    71         //a (very powerful) Instance Level permission:
    72         if (currentUser.isPermitted("winnebago:drive:eagle5")) {
    73             log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
    74                     "Here are the keys - have fun!");
    75         } else {
    76             log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
    77         }
    78 
    79         //all done - log out!
    80         currentUser.logout();
    81 
    82         System.exit(0);
    83     }
    84 }
    View Code

    这里说一下,对于没有授权的,登录需拿到用户信息产生的令牌(token)进行登录。

    token可以理解为用户令牌,登录的过程被抽象为Shiro验证令牌是否具有合法身份以及相关权限。

        使用用户的登录信息创建令牌

    UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        执行登录

    subject.login(token); // 登陆

     Shiro的核心部分是SecurityManager,它负责安全认证与授权。Shiro本身已经实现了所有的细节,用户可以完全把它当做一个黑盒来使用。

  • 相关阅读:
    Construct Binary Tree from Preorder and Inorder Traversal
    Construct Binary Tree from Inorder and Postorder Traversal
    Maximum Depth of Binary Tree
    Sharepoint 2013 创建TimeJob 自动发送邮件
    IE8 不能够在Sharepoint平台上在线打开Office文档解决方案
    TFS安装与管理
    局域网通过IP查看对方计算机名,通过计算机名查看对方IP以及查看在线所有电脑IP
    JS 隐藏Sharepoint中List Item View页面的某一个字段
    SharePoint Calculated Column Formulas & Functions
    JS 两个一组数组转二维数组
  • 原文地址:https://www.cnblogs.com/jedjia/p/Shiro.html
Copyright © 2011-2022 走看看