shiro框架


一、简介

1、简述shiro框架

一个用于应用程序安全验证和授权的 Java 安全框架。它提供了一系列的技术,例如认证、授权、会话管理和安全数据管理,可以帮助开发者更容易地实现应用程序安全性。

2、Shiro与SpringSecurity的对比

  • 1、SpringSecurity基于Spring开发,项目若使用Spring作为基础,配合SpringSecurity做权限更加方便,而Shiro需要和Spring进行整合开发;
  • 2、SpringSecurity功能比Shiro更加丰富些,例如安全维护方面
  • 3、SpringSecurity社区资源相比Shiro更加丰富
  • 4、Shiro的配置和使用比较简单,SpringSecurity上手复杂些
  • 5、Shiro依赖性低,不需要任何框架和容器,可以独立运行,SpringSecurity依赖Spring容器
  • 6、Shiro不仅仅可以使用在web中,他可以工作在任何环境中。在集群会话时Shiro最重要的一个好处或许就是它的会话独立于容器的。

3、基本功能

在这里插入图片描述

  • Authentication:⾝份认证/登录,验证⽤⼾是不是拥有相应的⾝份;
  • Authorization:授权,即权限验证,验证某个已认证的⽤⼾是否拥有某个权限;即判 断⽤⼾是否能进⾏什么操作。如:验证某个⽤⼾是否拥有某个⻆⾊。或者细粒度的验证某 个⽤⼾对某个资源是否具有某个权限;
  • Session Manager:会话管理,即⽤⼾登录后就是⼀次会话,在没有退出之前,它的所 有信息都在会话中;会话可以是普通 JavaSE 环境,也可以是 Web 环境的;
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,⽽不是明⽂存 储;
  • Web Support:Web ⽀持,可以⾮常容易的集成到Web 环境;
  • Caching:缓存,⽐如⽤⼾登录后,其⽤⼾信息、拥有的⻆⾊/权限不必每次去查,这样 可以提⾼效率;
  • Remember Me:记住我,这个是⾮常常⻅的功能,即⼀次登录后,下次再来的话可以⽴ 即知道你是哪个⽤⼾

4、Shiro架构

在这里插入图片描述

二、基本使用

1、环境搭建

1.1 prom文件

<dependencies>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.9.0</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

1.2 INI文件

  • Shiro获取权限相关信息,可以通过数据库获取,也可以通过INI配置文件获取
  • 在resource文件目录下新建shiro.ini文件
#定义⽤⼾信息 
#格式:⽤⼾名=密码,⻆⾊1,⻆⾊2,....
[users]
zhangsan=123,admin
lisi=456,manager,seller
wangwu=789,clerk
# ----------------

2、 登录认证

  • 1、收集用户身份、凭证,即用户名、密码
  • 2、调用Subject.login进行登录,如果失败将得到相应的AuthenticationException异常,根据异常提示用户错误信息否则登录成功
  • 3、创建自定义的Realm类,继承org.apache.shiro.realm.AuthenticatingRealm类,实现doGetAuthenticationInfo()方法
    在这里插入图片描述
  • 实现例子
public class Main {
    public static void main(String[] args) {
        //1、初始化获取SecurityManager
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        //2、获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        //3、创建token对象,web应用用户名密码从页面传递
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123");
        //4、完成登录
        try {
            subject.login(token);
            System.out.println("登录成功");
        }
        catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名不存在");
        }
        catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
        catch (AuthenticationException e) {
            throw new RuntimeException(e);
        }
    }
}

3、角色、授权

3.1 概念

  • 授权(访问控制),即在应用中控制谁访问哪些资源(如访问页面资源、编辑资源、页面操作等)。在授权中需要了解的几个关键对象:主题(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
  • 主体(Subject):访问应用的用户,在Shiro中使用Subject代表该用户。用户只有授权后才允许访问相应的资源
  • 资源(Resource):在应用中用户可以访问的URL,比如访问JSP页面、查看\编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只有授权后才能访问
  • 权限(Permission):安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权利。即权限表示在应用中用户不能访问某个资源,如:访问用户列表查看/新增/修改/删除用户数据(即很多时候都是CRUD式权限控制)等。权限代表了用户没有操作某个资源的权利,即反映在某个资源上的操作允不允许
  • Shiro支持粗粒权限(如用户模板的所有权限)细粒度权限(操作某个用户的权限,即实例级别)
  • 角色(Role):权限的集合,一般情况下会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师都是角色,不同的角色拥有一组不同的权限

3.2 授权方式

  • 1、编程式:通过写if/else授权代码完成
if(subject.hasRole("admin")){
	//有权限
}else{
	//无权限
}
  • 2、注解式:通过在执行的Java方法上防置相应的注解完成,没有权限将抛出相应的异常
@RequiresRole("admin")
public void hello(){
	//有权限
}
  • 3、JSP/GSP标签:在JSP/GSP页面通过相应的标签完成
<shiro:hasRole name="admin">
<!--有权限-->
</shiro:hasRole>

3.3 授权流程

  • 首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityMannager,而SecurityMannager接着回委托给Authorizer
  • Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例
  • 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限
  • Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole*会返回true,否则返回false表示授权失败
    在这里插入图片描述

3.4 授权实例

在这里插入图片描述

try {
            subject.login(token);
            System.out.println("登录成功");
            //5、判断角色
            boolean hasRole = subject.hasRole("role1");
            System.out.println("是否拥有此角色="+hasRole);
            //6、判断权限
            boolean permitted = subject.isPermitted("user:insert");
            System.out.println("是否拥有此权限="+hasRole);
            //也可以用checkPermission方法,但没有返回值,没权限抛异常
            subject.checkPermission("user:delete");
        }
        catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名不存在");
        }
        catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
        catch (AuthenticationException e) {
            throw new RuntimeException(e);
        }

4、Shiro加密(MD5)

public class ShiroMD5 {
    public static void main(String[] args) {
        //密码明文
        String password="123";
        //使用MD5加密
        Md5Hash md5Hash = new Md5Hash(password);
        System.out.println(md5Hash);
        //在密码明文后再拼接一个字符串,然后再进行加密,加盐
        Md5Hash md5Hash1 =new Md5Hash(password,"wangkay");
        System.out.println("md5Hash1 = " + md5Hash1.toHex());
        //为了保证安全,避免破解还可以多次迭代加密,加很多盐
        Md5Hash md5Hash2 =new Md5Hash(password,"wangkay",3);
        System.out.println("md5Hash2 = " + md5Hash2);
        //使用父类进行带盐3次加密
        SimpleHash simpleHash = new SimpleHash("MD5",password,"wangkay",3);
        System.out.println("simpleHash = " + simpleHash.toHex());
    }
}

5、Shiro自定义登录认证

在这里插入图片描述

[main]
md5CredentialsMatcher=org.apache.shiro.authc.credential.Md5credentialsMatcher
md5CredentialsMatcher.hashIterations=3

myrealm=org/example/maintest/MyRealm.java
myrealm.credentialsMatcher=$md5CredentialsMatcher
securityManager.realms=$myrealm

[users]
zhangsan=0a6b3234beefb30de9205eb3285664e0,role1,role2
lisi=456,manager,seller
wangwu=789,clerk
# ----------------
[roles]
role1:user:insert,user:select
public class MyRealm extends AuthenticatingRealm {
    //自定义登录认证方法,Shiro的login的方法底层会调用该类的认证方法进行认证
    //需要配置自定义的realm生效,在ini文件中可以配置,在springboot中配置
    //该方法只是进行获取对比的信息,认证步骤还是按照Shiro底层逻辑认证完成
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1、获取身份信息
        String principal = token.getPrincipal().toString();
        //2、获取凭证信息
        String password = new String((char[]) token.getCredentials());
        System.out.println("认证用户信息:"+principal+"----"+password);
        //3、访问数据库,获取存储的用户信息
        if (principal.equals("zhangsan")){
            //数据库中存储的加盐3次迭代的密码
            String pwdInfo  = "0a6b3234beefb30de9205eb3285664e0";
            //创建封装校验逻辑对象,封装
            AuthenticationInfo info = new SimpleAuthenticationInfo(
                    token.getPrincipal(),
                    pwdInfo,
                    ByteSource.Util.bytes("wangkay"),
                    token.getPrincipal().toString());

        }
        //4、创建封装校验逻辑对象,封装数据返回

        return null;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangkay88

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值