Shiro

跟着大宇学Shiro--------目录帖

三个核心组件:Subject, SecurityManager 和 Realms. Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。   Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。   SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。   Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。   从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。   Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

shiro实现原理理解

在这里插入图片描述

 

也就是说对于我们而言,最简单的一个 Shiro 应用: 应用代码通过 Subject 来进行认证和授权,而 Subject 又委托给 SecurityManager; 我们需要给 Shiro 的 SecurityManager 注入 Realm,从而让 SecurityManager 能得到合法的用户及其权限进行判断。

在这里插入图片描述

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 服务器); SessionDAO:DAO 大家都用过,数据访问对象,用于会话的 CRUD,比如我们想把 Session保存到数据库,那么可以实现自己的 SessionDAO,通过如 JDBC 写到数据库;比如想把Session 放到 Memcached 中,可以实现自己的 Memcached SessionDAO;另外 SessionDAO中可以使用 Cache 进行缓存,以提高性能; CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能 Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于如密码加密

shiro认证功能(Authentication)流程

在这里插入图片描述

@Test
public void testHelloworld() {
//1、获取 SecurityManager 工厂,此处使用 Ini 配置文件初始化 SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager> factory =
new IniSecurityManagerFactory("classpath:shiro.ini");
//2、得到 SecurityManager 实例 并绑定给 SecurityUtils
org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3、得到 Subject 及创建用户名/密码身份验证 Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
// UsernamePasswordToken 继承
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
try {
//4、登录,即身份验证
    subject.login(token);
} catch (AuthenticationException e) {
//5、身份验证失败
}
Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录
//6、退出
subject.logout();

shiro授权实现的方式以及流程

  • 基于角色的访问控制(隐式角色)

  • 基于资源的访问控制(显示角色) 实现方式:

    // 1. 编程式(单个和多个角色)
    subject.hasRole(“admin”), Array.aslist("admin1","admin2");
    ​
    //2. 注解
    @RequiresRoles("admin")
    ​
    //3. 页面控制
    <shiro:hasRole name="admin">
    ​
    //4. shiro配置文件中配置
     <property name="filterChainDefinitions">
                <value>
                    /commons/** = anon
                    /plugins/** = anon
                    /assets/** = anon
                    /css/** = anon
                    /js/** = anon
                    /img/** = anon
                    /fonts/** = anon
                    /bootstrap/** = anon
                    /login = anon
                    /interface/** = anon
                    /** = user
                    
                </value>
    </property>

    shiro 拦截器规则:

img

自定义realm

/**
 * 自定义Realm
 * (1)AuthenticatingRealm:shiro中的用于进行认证的领域,实现doGetAuthentcationInfo方法实现用户登录时的认证逻辑;
 * (2)AuthorizingRealm:shiro中用于授权的领域,实现doGetAuthrozitionInfo方法实现用户的授权逻辑,AuthorizingRealm继承了AuthenticatingRealm,
 * 所以在实际使用中主要用到的就是这个AuthenticatingRealm类;
 * (3)AuthenticatingRealm、AuthorizingRealm这两个类都是shiro中提供了一些线程的realm接口
 * (4)在与spring整合项目中,shiro的SecurityManager会自动调用这两个方法,从而实现认证和授权,可以结合shiro的CacheManager将认证和授权信息保存在缓存中,
 * 这样可以提高系统的处理效率。    
 *
 */
public class UserRealm extends AuthorizingRealm{
​
    @Autowired
    private UserService userSerivce;
​
    /**
     * 执行认证逻辑
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
        System.out.println("执行认证逻辑");
​
        //编写shiro判断逻辑,判断用户名和密码
        //1.判断用户名  token中的用户信息是登录时候传进来的
        UsernamePasswordToken token = (UsernamePasswordToken)arg0;
​
        User user = userSerivce.findByName(token.getUsername());
​
        if(user==null){
            //用户名不存在
            return null;//shiro底层会抛出UnKnowAccountException
        }
​
        //2.判断密码
        //第二个字段是user.getPassword(),注意这里是指从数据库中获取的password。第三个字段是realm,即当前realm的名称。
        //这块对比逻辑是先对比username,但是username肯定是相等的,所以真正对比的是password。
        //从这里传入的password(这里是从数据库获取的)和token(filter中登录时生成的)中的password做对比,如果相同就允许登录,
        // 不相同就抛出IncorrectCredentialsException异常。
        //如果认证不通过,就不会执行下面的授权方法了
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
​
    /**
     * 执行授权逻辑
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
​
        //doGetAuthorizationInfo方法可能会执行多次,权限判断次数多少,就会执行多少次
        System.out.println("执行授权逻辑1");
        System.out.println("执行授权逻辑2");
        
        //给资源进行授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        
        //添加资源的授权字符串
        //info.addStringPermission("user:add");
        
        //到数据库查询当前登录用户的授权字符串
        //获取当前登录用户
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();
        User dbUser = userSerivce.findById(user.getId());
        
        info.addStringPermission(dbUser.getPerms());
        
        return info;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值