四、Shiro认证

四、Shiro认证

4.1、认证

身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式就是通过核对用户输入的用户名和口令,看其与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。

4.2、shiro认证关键对象

  • subject:主体

    访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体。

  • Principal:身份信息

    主体(Subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮件地址等,一个主体可以有多个身份,但必须有一个主身份(Primary Principal)。

  • credential:凭证信息

    只有主体自己知道的安全信息,比如密码、证书等

4.3、认证流程

在这里插入图片描述

4.4、认证开发

1、创建项目并引入依赖

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

添加resource目录

在这里插入图片描述

 <!--引入-Shrio-开始-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!--引入-Shrio-结束-->

在这里插入图片描述

在这里插入图片描述

2、引入shiro配置文件并加入如下配置

shiro配置文件以ini结尾,.ini复杂数据格式

创建配置文件shiro.ini

在这里插入图片描述

在这里插入图片描述

ini配置文件,用来给学习shiro书写相关权限数据,后期整合spring不用书写

#相当于配了三个用户
[users]
xiaochen=123
zhangsan=123456
lisi=789

在这里插入图片描述

在这里插入图片描述

3、认证代码
package org.hz52;

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.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

/**
 * @Program: shiro_demo
 * @Description:
 * @Author: 52Hz
 * @CreationTime: 2021年10月16日 13:12 星期六
 **/
public class testAuthenticator {
    public static void main(String[] args) {

        //1.创建安全管理器
        DefaultSecurityManager securityManager = new DefaultSecurityManager();


        //2、给安全管理器设置realm:设置为ini里面的数据
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));

        //3、SecurityUtils 给全局安全工具类设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);

        //4、关键对象 : subject主体
        Subject subject = SecurityUtils.getSubject();


        //5、创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");

        try {
            System.out.println("认证状态:" + subject.isAuthenticated());
            subject.login(token);//用户认证
            System.out.println("认证状态:" + subject.isAuthenticated());

        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("认证失败:" + token.getUsername() + "用户名不存在");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("认证失败:" + token.getUsername() + "密码错误");
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

在这里插入图片描述

在这里插入图片描述

查看类的关系图

在这里插入图片描述

查看实现类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.5、自定义Realm

上面的程序使用Shiro自带的IniRealm,Inirealm从配置文件中读取用户的信息,大部分情况下需要从系统的数据库中用户信息,所以需要自定义realm。

1、shiro提供的Realm

在这里插入图片描述

2、根据源码认证使用的是SimpleAcSimcountRealm

在这里插入图片描述

在这里插入图片描述

SimpleAcSimcountRealm的部分源码中有两个方法:一个是认证,一个是授权

在这里插入图片描述

2、自定义Realm
package org.hz52.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;

/**
 * @Program: shiro_demo
 * @Description: 自定义Realm,将认证/授权数据来源转为数据库的实现
 * @Author: 52Hz
 * @CreationTime: 2021年10月16日 14:44 星期六
 **/
public class CustmerRealm extends AuthorizingRealm {

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //在token中获取用户名
        String principal = (String) token.getPrincipal();
        System.out.println(principal);

        //根据用户身份信息使用jdbc mybatis查询相关数据库
        if ("xiaochen".equals(principal)) {

            //SimpleAuthenticationInfo
            // 参数1:数据库中的用户名
            // 参数2:数据库中的密码
            // 参数3:当前realm的名称this.getName()
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, "123d", this.getName());

            return simpleAuthenticationInfo;
        }


        return null;
    }
}
4、使用自定义Realm

无需ini文件

package org.hz52;

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.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.hz52.realm.CustmerRealm;

/**
 * @Program: shiro_demo
 * @Description: 使用自定义Realm
 * @Author: 52Hz
 * @CreationTime: 2021年10月16日 14:48 星期六
 **/
public class testCustmerAuthenticator {

    public static void main(String[] args) {

        //创建securityManager
        DefaultSecurityManager securityManager = new DefaultSecurityManager();

        //设置自定义Realm
        securityManager.setRealm(new CustmerRealm());

        //将安全工具类设置Realm
        SecurityUtils.setSecurityManager(securityManager);

        //通过安全工具类获取subject
        Subject subject = SecurityUtils.getSubject();

        //创建token
        UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");

        try {
            subject.login(token);
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println(token.getUsername() + "用户名错误");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println(token.getUsername() + "密码错误");
        }


    }


}

4.6、使用MD5和Salt

实际应用是将盐和散列后的值存在数据库中,自动realm从数据库取出盐和加密后的值由shiro完成密码校验。

1、自定义md5+salt

在这里插入图片描述

在这里插入图片描述

错误加密(未加密)

在这里插入图片描述

   //创建一个md5算法
        //当前没有进行加密
        Md5Hash md5Hash = new Md5Hash();
        //不设置散列次数则默认只做MD5
        md5Hash.setBytes("123".getBytes());
        System.out.println(md5Hash.toHex());
        System.out.println(md5Hash.toBase64());
        System.out.println(md5Hash.toString());
真正的加密

在这里插入图片描述

 		//使用md5
        //使用构造方法才可以生成密钥
         Md5Hash md5Hash=new Md5Hash("123");
         System.out.println(md5Hash.toHex());
使用MD5+Salt

在这里插入图片描述

         //使用md5+salt
        Md5Hash md5Hash1=new Md5Hash("123","X0#31");
        System.out.println(md5Hash1.toHex());
使用MD5+Salt+Hash

在这里插入图片描述

        //使用md5+salt+hash散列(一般1024/2048)
        Md5Hash md5Hash2 = new Md5Hash("123", "X0#31", 1024);
        System.out.println(md5Hash2.toHex());


package org.hz52;

import org.apache.shiro.crypto.hash.Md5Hash;

/**
 * @Program: shiro_demo
 * @Description:
 * @Author: 52Hz
 * @CreationTime: 2021年10月16日 16:06 星期六
 **/
public class testShiroMD5 {

    public static void main(String[] args) {

        //创建一个md5算法
        //当前没有进行加密
//        Md5Hash md5Hash = new Md5Hash();
//        //不设置散列次数则默认只做MD5
//        md5Hash.setBytes("123".getBytes());
//        System.out.println(md5Hash.toHex());
//        System.out.println(md5Hash.toBase64());
//        System.out.println(md5Hash.toString());


        //使用md5
        //使用构造方法才可以生成密钥
        Md5Hash md5Hash = new Md5Hash("123");
        System.out.println(md5Hash.toHex());


        //使用md5+salt
        Md5Hash md5Hash1 = new Md5Hash("123", "X0#31");
        System.out.println(md5Hash1.toHex());


        //使用md5+salt+hash散列
        Md5Hash md5Hash2 = new Md5Hash("123", "X0#31", 1024);
        System.out.println(md5Hash2.toHex());


    }

}



202cb962ac59075b964b07152d234b70
93018183dbbdc94a9fcf3166665bbaf5
6abca58de7461f2b5d795d3a6e79aaa6
2、测试
测试-明文

数据库返回明文则制作equals

新建CustmerMD5Realm
package org.hz52.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;

/**
 * @Program: shiro_demo
 * @Description: 使用自定义realm加入md5+salt+hash
 * @Author: 52Hz
 * @CreationTime: 2021年10月18日 9:25 星期一
 **/
public class CustmerMD5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {


        //获取身份信息
        String principal = (String) token.getPrincipal();


        //根据用户名查询数据库
        if ("xiaochen".equals(principal)) {
            return new SimpleAuthenticationInfo(principal, "123", this.getName());
        }


        return null;
    }
}
新建testCustmerMD5Authenticator
package org.hz52;

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.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.hz52.realm.CustmerMD5Realm;

/**
 * @Program: shiro_demo
 * @Description:
 * @Author: 52Hz
 * @CreationTime: 2021年10月18日 9:27 星期一
 **/
public class testCustmerMD5Authenticator {

    public static void main(String[] args) {

        //1、创建安全管理器
        DefaultSecurityManager securityManager = new DefaultSecurityManager();


        //2、注入realm
        securityManager.setRealm(new CustmerMD5Realm());

        //3、将安全管理器注入安全工具
        SecurityUtils.setSecurityManager(securityManager);

        //4、通过安全工具类获取subject
        Subject subject = SecurityUtils.getSubject();


        //5、认证
        UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");


        try {
            subject.login(token);
            System.out.println("登陆成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        }


    }


}

在这里插入图片描述

测试-MD5

数据库返回md5,使用的时候需要切换验证

修改CustmerMD5Realm
package org.hz52.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;

/**
 * @Program: shiro_demo
 * @Description: 使用自定义realm加入md5+salt+hash
 * @Author: 52Hz
 * @CreationTime: 2021年10月18日 9:25 星期一
 **/
public class CustmerMD5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {


        //获取身份信息
        String principal = (String) token.getPrincipal();


        //根据用户名查询数据库
        if ("xiaochen".equals(principal)) {
            return new SimpleAuthenticationInfo(principal, "202cb962ac59075b964b07152d234b70", this.getName());
        }


        return null;
    }
}
修改testCustmerMD5Authenticator

使用的时候需要切换验证

package org.hz52;

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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.hz52.realm.CustmerMD5Realm;

/**
 * @Program: shiro_demo
 * @Description:
 * @Author: 52Hz
 * @CreationTime: 2021年10月18日 9:27 星期一
 **/
public class testCustmerMD5Authenticator {

    public static void main(String[] args) {

        //1、创建安全管理器
        DefaultSecurityManager securityManager = new DefaultSecurityManager();


        //2、注入realm

        //设置realm使用hash凭证匹配器
        CustmerMD5Realm realm = new CustmerMD5Realm();
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5");
        realm.setCredentialsMatcher(credentialsMatcher);


        securityManager.setRealm(realm);

        //3、将安全管理器注入安全工具
        SecurityUtils.setSecurityManager(securityManager);

        //4、通过安全工具类获取subject
        Subject subject = SecurityUtils.getSubject();


        //5、认证
        UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");


        try {
            subject.login(token);
            System.out.println("登陆成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        }


    }


}
测试-MD5+Salt
修改CustmerMD5Realm
package org.hz52.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;
import org.apache.shiro.util.ByteSource;

/**
 * @Program: shiro_demo
 * @Description: 使用自定义realm加入md5+salt+hash
 * @Author: 52Hz
 * @CreationTime: 2021年10月18日 9:25 星期一
 **/
public class CustmerMD5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {


        //获取身份信息
        String principal = (String) token.getPrincipal();


        //根据用户名查询数据库
        if ("xiaochen".equals(principal)) {


            //参数1:数据库用户名    参数2:数据库MD5+Salt之后的密码    参数3:注册
            return new SimpleAuthenticationInfo(principal,
                    "93018183dbbdc94a9fcf3166665bbaf5",
                    ByteSource.Util.bytes("X0#31"),
                    this.getName());
        }


        return null;
    }
}
修改testCustmerMD5Authenticator
package org.hz52;

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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.hz52.realm.CustmerMD5Realm;

/**
 * @Program: shiro_demo
 * @Description:
 * @Author: 52Hz
 * @CreationTime: 2021年10月18日 9:27 星期一
 **/
public class testCustmerMD5Authenticator {

    public static void main(String[] args) {

        //1、创建安全管理器
        DefaultSecurityManager securityManager = new DefaultSecurityManager();


        //2、注入realm

        //设置realm使用hash凭证匹配器
        CustmerMD5Realm realm = new CustmerMD5Realm();
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5");
        realm.setCredentialsMatcher(credentialsMatcher);


        securityManager.setRealm(realm);

        //3、将安全管理器注入安全工具
        SecurityUtils.setSecurityManager(securityManager);

        //4、通过安全工具类获取subject
        Subject subject = SecurityUtils.getSubject();


        //5、认证
        UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");


        try {
            subject.login(token);
            System.out.println("登陆成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        }


    }


}
测试-MD5+Salt+Hash
修改CustmerMD5Realm
package org.hz52.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;
import org.apache.shiro.util.ByteSource;

/**
 * @Program: shiro_demo
 * @Description: 使用自定义realm加入md5+salt+hash
 * @Author: 52Hz
 * @CreationTime: 2021年10月18日 9:25 星期一
 **/
public class CustmerMD5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {


        //获取身份信息
        String principal = (String) token.getPrincipal();


        //根据用户名查询数据库
        if ("xiaochen".equals(principal)) {


            //参数1:数据库用户名    参数2:数据库MD5+Salt之后的密码    参数3:注册
            return new SimpleAuthenticationInfo(principal,
                    "6abca58de7461f2b5d795d3a6e79aaa6",
                    ByteSource.Util.bytes("X0#31"),
                    this.getName());
        }


        return null;
    }
}
修改testCustmerMD5Authenticator
package org.hz52;

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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.hz52.realm.CustmerMD5Realm;

/**
 * @Program: shiro_demo
 * @Description:
 * @Author: 52Hz
 * @CreationTime: 2021年10月18日 9:27 星期一
 **/
public class testCustmerMD5Authenticator {

    public static void main(String[] args) {

        //1、创建安全管理器
        DefaultSecurityManager securityManager = new DefaultSecurityManager();


        //2、注入realm

        //设置realm使用hash凭证匹配器
        CustmerMD5Realm realm = new CustmerMD5Realm();
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法
        credentialsMatcher.setHashAlgorithmName("md5");
        //设置散列次数
        credentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(credentialsMatcher);


        securityManager.setRealm(realm);

        //3、将安全管理器注入安全工具
        SecurityUtils.setSecurityManager(securityManager);

        //4、通过安全工具类获取subject
        Subject subject = SecurityUtils.getSubject();


        //5、认证
        UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");


        try {
            subject.login(token);
            System.out.println("登陆成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        }


    }


}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值