ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

shiro认证

2021-03-29 17:31:51  阅读:267  来源: 互联网

标签:Realm securityManager 认证 token new zhangsan shiro subject


Shiro

代码地址gitee

1 认证

1.1 使用ini配置文件来实现认证

shiro实现简单的认证,用户名的账号和密码放在了根目录下的shiro.ini文件中

[users]
zhangsan=123123
lisi=123123

在设置securityManager的Realm的时候,选择new一个IniRealm,传入shiro.ini的路径

// 创建安全管理器对象
DefaultSecurityManager securityManager = new DefaultSecurityManager();
// 给安全管理器设置realm
securityManager.setRealm(new IniRealm("classpath:shiro.ini"));

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

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

// 创建令牌
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123123");

// 用户认证
try {
  subject.login(token);
} catch (UnknownAccountException e) {
  e.printStackTrace();
  System.out.println("账号不存在");
} catch (IncorrectCredentialsException e) {
  e.printStackTrace();
  System.out.println("密码错误");
}

1.2 使用自己定义的Realm来实现认证

我们自定义的Realm需要继承AuthorizingRealm,重写doGetAuthorizationInfo()授权方法和doGetAuthenticationInfo()认证方法

通过追溯源码可以得到如下依赖图:

  • AuthenticatingRealm 认证的Realm抽象类
  • AuthorizingRealm 授权的Realm抽象类
  • 用户名比较是在SimpleAccountRealm中的doGetAuthenticationInfo 完成用户名校验
  • 密码是在AuthenticatingRealm中的assertCredentialsMatch完成校验
  • 通过图可以看出,继承AuthorizingRealm就可以重写认证AuthenticatingRealm和授权AuthorizingRealm两个抽象类的方法

在这里插入图片描述

自定义Realm类

public class CustomerRealm extends AuthorizingRealm {

    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
  
    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // token中获取用户名
        String principal = (String) token.getPrincipal();
        System.out.println("principal = " + principal);

        // 根据用户名获取数据,例如 queryUserByUsername(principal);
      	// 这里模拟数据库中获取数据
        if ("zhangsan".equals(principal)) {
            /**
             * 参数1: 返回数据库中正确的用户名
             * 参数2: 密码
             * 参数3: 提供当前的realm的名字,直接调用父类的getName()方法
             */
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo("zhangsan", "123123", this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}

下述测试自定义Realm类的时候,只是将new IniRealm()改成new自己定义的Realm。后期和数据中的账号密码作比较是在自己定义的Realm中进行的。

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

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

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

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

// 创建token
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","123123");

// 登录
try {
  subject.login(token);
} catch (AuthenticationException e) {
  e.printStackTrace();
}

1.3 自定义Realm的md5加密加盐比较

md5加密 是不可逆的,同一数据在进行md5加密后得到的加密字符串相同。

自定义MD5Realm类

public class CustomerMD5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

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

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

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

            /**
             * 参数一: 数据库中的密码
             * 参数二:md5+salt之后的密码
             * 参数三:盐值
             * 参数四:当前realm的名称
             */
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                    "zhangsan",
                    "f997c74487a098c9477da3a0c10944a5",
                    ByteSource.Util.bytes("s0*5ps"),
                    getName());
            return info;
        }

        return null;
    }
}

md5加密测试类

相比之前不同的是,我们在new Realm之后,对Realm进行设置加密算法和迭代次数。迭代次数不同得到的MD5加密字符串也不同。

扩展:

​ 这里的盐值我们后期可以通过字符串生成工具来随机生成字符串,并将其存入数据库中,在进行登录的时候,用相同的加密原则来进行判断。例如,我们注册的时候是将盐值加载密码后面再进行加密,我们登录的时候就要将数据库中的盐值加在密码后面。

public class TestCustomerMD5RealmAuthenticator {
    public static void main(String[] args) {
        // 创建安全管理器
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        // 注入realm
        CustomerMD5Realm realm = new CustomerMD5Realm();
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 注册算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        // 散列次数
//        hashedCredentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(hashedCredentialsMatcher);

        // 为securityManager设置Realm
        securityManager.setRealm(realm);

        // 设置securityManager
        SecurityUtils.setSecurityManager(securityManager);

        // 获取subject对象
        Subject subject = SecurityUtils.getSubject();

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

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

    }
}

标签:Realm,securityManager,认证,token,new,zhangsan,shiro,subject
来源: https://blog.csdn.net/weixin_43847957/article/details/115306341

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有