shiro01

shiro

问题1:什么是shiro?它是做什么的?

答:shiro是apache公司提供的一种安全框架。它在项目中主要用于进行权限控制


在项目要进行权限控制,一般会采用下列技术:

  1. spring security
  2. shiro

相同点:这两种技术,都可以进行权限控制

不同点:

  • spring security入门有门槛,上手有一定难度, shiro上手很简单
  • spring security这种技术它依赖于spring,项目只有用到spring才可以使用它,shiro不依赖spring, 项目中有没有spring都可以使用shiro
  • spring security它进行权限控制功能会更强大,但shiro已经足够满足日常需求 

------------------------------------------------------------------------------------------
shiro中的几个核心概念:

  1. 认证(登录)判断用户是否可以登录成功
  2. 授权  (登录成功以的用户,访问资源时,得到用户的访问权限)

shiro中的几个核心对象:

Security Manager:安全管理器

  • 作用:shiro的认证操作、授权操作都要由它来执行 

Subject:主体

  • 作用:它用于进行认证、授权

Realm:领域对象

  • 作用:它是一个类,用于封装认证、授权的方法

Session:会话对象

  • 作用:当用户认证成功以后,通过认证的主体(subject)将会存放到shiro的session中

    
shiro的基本配置流程 

  1. 基于ini文件认证(登录)
  2. 基于realm类进行认证(登录)
  3. 认证时采用md5加密
  4. 授权(基于ini)
  5. 授权(基于realm)

基于ini文件认证(登录)

步骤:    
1、创建一个maven结构的java项目(非web)

2、导入shiro-core依赖

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.2.6</version>
    </dependency>

    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>

3、创建 resources目录

4、在resources目录下,创建一个配置文件 shiro.ini(用于封装用户名,密码)--------实际应用中,不可能将用户名,密码写入文件

#封装用户信息
[users]
jack=111
andy=222

5、编写测试类,测试代码

package org.java.d91.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

/**
 * 基于ini文件的认证(登录 )
 */
public class Demo1 {

    public static void main(String[] args) {

        //创建工厂类,用于产生securityManager
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");

        //通过工厂类,产生SecurityManager
        SecurityManager securityManager = factory.getInstance();

        //将安全管理器,设置到当前运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //得到主体
        Subject subject = SecurityUtils.getSubject();

        //创建一个令牌(token),用于封装用户名与密码
        UsernamePasswordToken  token = new UsernamePasswordToken("jack","111");


        try {
            //通过主体执行认证操作
            subject.login(token);

            //判断是否认证成功
            if(subject.isAuthenticated()){
                System.out.println("认证成功.....");
            }

            System.out.println("--------------------------------------------");
            subject.logout();//登出(退出登录)

            if(subject.isAuthenticated()){
                System.out.println("已登录.....");
            }else{
                System.out.println("已退出");
            }

        } catch (UnknownAccountException e) {
            System.out.println("用户名不存在!");
        } catch (IncorrectCredentialsException e){
            System.out.println("密码错码");
        }


    }
}
  • UnknownAccountException:未知用户异常(用户名不存在)
  • IncorrectCredentialsException:密码不区配

shiro认证的过程:

1、它会将用户名与密码封装成一个令牌usernamepasswordToken,当subject执行login()方法时,传递 token,
    
2、securityManager会从令牌中取出用户名,判断用户是否存在

  • 如果用户名存在,则取出该用户的正确密码,与用户输入的密码的进行对比
  • 如果用户名不存在,则直接产生异常UnknownAccountException

3、如果密码一致,则认证成功,认证成功后,shiro将会把主体subject存放到shiro自己的sessioin中。如果密码不一致,则产生异常:IncorrectCredentialsException

@@@在实际应用中,不可能将用户信息写文件,数据都是存放在数据库中,需要读取数据库

基于realm类进行认证(登录)

1、创建工程(maven的java项目)

2、创建一个Realm类(封装认证、授权的方法),继承于:AuthorizingRealm,并且重写父类的方法

package org.java.d91.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * 领域对象,用于封装认证、授权的方法
 */
public class MyRealm extends AuthorizingRealm {

    //授权(得到用户的访问权限)
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    //认证(登录)
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        return null;
    }
}

3、编写shiro2.ini文件 

[main]

#声明一个变量,指向realm类
myRealm=org.java.d91.realm.MyRealm

#指定安全管理器通过哪一个realm进行认证、授权
securityManager.realms=$myRealm

4、编写测试类

package org.java.d91.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

/**
 * 基于realm的认证(登录 )
 */
public class Demo3 {

    public static void main(String[] args) {

        //创建工厂类,用于产生securityManager
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro2.ini");

        //通过工厂类,产生SecurityManager
        SecurityManager securityManager = factory.getInstance();

        //将安全管理器,设置到当前运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //得到主体
        Subject subject = SecurityUtils.getSubject();

        //创建一个令牌(token),用于封装用户名与密码
        UsernamePasswordToken  token = new UsernamePasswordToken("andy","111");


        try {
            //通过主体执行认证操作
            subject.login(token);

            //判断是否认证成功
            if(subject.isAuthenticated()){
                System.out.println("认证成功.....");
            }
        } catch (UnknownAccountException e) {
            System.out.println("用户名不存在!");
        } catch (IncorrectCredentialsException e){
            System.out.println("密码错码");
        }


    }
}

    5、编写MyRealm类中,认证的方法 doGetAuthenticationInfo

    //认证(登录)
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //从token中,取得主要信息(用户名)
        String principal = (String) token.getPrincipal();

        //根据用户名查询数据库,判断,用户是否存在(此处模拟查询数据库,如果用户是jack,该用户不存在)
        if(principal.equals("jack")){
            //jack不能登录
            return null;//如果该方法,返回null,则表示,用户不存在,系统将抛出异常UnknownAccountException
        }

        //如果用户名存在,则根据返回该 用户名在数据库中的正确密码(此处,模拟从数据库中取出来的密码111)
        String pwd ="111";

        //将:主要信息(princilpal),该用户名的正确密码,进行封装,通过安全管理器,与用户输入的密码进行对比
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,pwd,"myrealm");

        return info;
    }

在实际应用中,存放在数据库中的密码,一定是加密后的密码,最常用的加密方式就是md加密

md5是一种不可逆的加密算法

关键配置

[main]

#指定凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher

#指定,采用的加密方式
credentialsMatcher.hashAlgorithmName=md5

#指定加密次数
credentialsMatcher.hashIterations=3

#指定,用于认证的realm
myrealm= org.java.d91.realm.MyRealm

# 指定当前realm类,采用哪一种凭证匹配器进行加密
myrealm.credentialsMatcher=$credentialsMatcher

#指定安全管理器,引用哪一个realm类
securityManager.realms=$myrealm
    //认证(登录)
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        System.out.println("========================系统正在调用doGetAuthenticationInfo方法,进行认证");
        //从token中,取得主要信息(用户名)
        String principal = (String) token.getPrincipal();

        //根据用户名查询数据库,判断,用户是否存在(此处模拟查询数据库,如果用户是jack,该用户不存在)
        if(principal.equals("jack")){
            //jack不能登录
            return null;//如果该方法,返回null,则表示,用户不存在,系统将抛出异常UnknownAccountException
        }

        //如果用户名存在,则根据返回该 用户名在数据库中的正确密码(此处,模拟从数据库中取出来的密码111)
        String pwd ="4ebe4ae946ee2d290a499c6e44497090";
        String salt="accp";

        //将:主要信息(princilpal),该用户名的正确密码,进行封装,通过安全管理器,与用户输入的密码进行对比
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,pwd, ByteSource.Util.bytes(salt),"myrealm");

        return info;
    }

------------------------------------------------------------------------------------------------------

shiro基于reaml类进行授权

shiro在执行的时候,是先进行认证,再进行授权

  • 如果我们在代码中,没有进行任何权限、角色的判断操作,系统将不会调用授权的方法
  • 如果进行了任何的权限、角色判断,系统将会马上调用realm类中授权的方法从数据库加载权限或角色
    //授权(得到用户的访问权限)
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("=============================系统正在调用doGetAuthorizationInfo方法,进行授权");

        //从principals取得用户的主要凭证(认证的方法,返回的info对象中的第一个参数)
        String principal = (String) principals.getPrimaryPrincipal();

        //根据用户信息principal,查询数据库,得到用户的访问权限 (模拟数据库查询 )
        List<String> list = new ArrayList<String>();
        list.add("user:add");
        list.add("user:del");

        //将查询到的权限,进行封装
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(list);

        return info;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值