Shiro 权限管理入门之认证与授权,Java后端社招面试经历

在这里插入图片描述

编写进行认证的代码:


public class TestAuthenticator {

    public static void main(String[] args) {

        // 创建安全管理器对象

        DefaultSecurityManager securityManager = new DefaultSecurityManager();

        // 给安全管理器设置realm, 从配置文件中获取数据

        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));

        // 给全局安全工具类设置默认安全管理器

        SecurityUtils.setSecurityManager(securityManager);

        // 获取主体对象

        Subject subject = SecurityUtils.getSubject();

        // 创建token令牌

        UsernamePasswordToken token = new UsernamePasswordToken("zhenyu", "123");

        try {

            // 用户登录

            System.out.println("认证状态:" + subject.isAuthenticated());

            subject.login(token);

            System.out.println("认证状态:" + subject.isAuthenticated());

        } catch (UnknownAccountException e) { // 用户名不存在异常

            e.printStackTrace();

            System.out.println("认证失败: 用户名不存在!");

        } catch (IncorrectCredentialsException e) { // 密码错误异常

            e.printStackTrace();

            System.out.println("认证失败: 密码错误!");

        }

    }

} 

  • DisabledAccountException(帐号被禁用)

  • LockedAccountException(帐号被锁定)

  • ExcessiveAttemptsException(登录失败次数过多)

  • ExpiredCredentialsException(凭证过期)

自定义 Realm


SimpleAccountRealm

上边的程序使用的是 Shiro 自带的 IniRealmIniRealmini配置文件 中读取用户的信息,实际中大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义 Realm。

Shiro 提供过的 Realm:

在这里插入图片描述

根据认证源码,认证使用的是 SimpleAccountRealm

在这里插入图片描述

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

认证方法 doGetAuthenticationInfo:

在这里插入图片描述

开发自定义 Realm

自定义 Realm,编写一个 CustomerRealm:


/**

 * 自定义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);

        // 根据身份信息连接数据库查询相关数据库

        if ("zhenyu".equals(principal)) {

            // 参数1:返回数据库中正确的用户名

            // 参数2:返回数据库中正确密码

            // 参数3:提供当前realm的名字 this.getName();

            return new SimpleAuthenticationInfo(principal, "123", this.getName());

        }

        return null;

    }

} 

使用自定义 Realm 进行认证:


/**

 * 使用自定义realm

 */

public class TestCustomerRealmAuthenticator {

    public static void main(String[] args) {

        // 创建securityManager

        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();

        // 设置自定义realm

        defaultSecurityManager.setRealm(new CustomerRealm());

        // 给全局安全工具类设置默认安全管理器

        SecurityUtils.setSecurityManager(defaultSecurityManager);

        // 通过安全工具类获取subject

        Subject subject = SecurityUtils.getSubject();

        // 创建token

        UsernamePasswordToken token = new UsernamePasswordToken("zhenyu", "123");

        try {

            subject.login(token);

            System.out.println("认证状态: " + subject.isAuthenticated());

        } catch (UnknownAccountException e) {

            e.printStackTrace();

            System.out.println("用户名错误!");

        } catch (IncorrectCredentialsException e) {

            e.printStackTrace();

            System.out.println("密码错误!");

        }

    }

} 

MD5 和 Salt


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

在这里插入图片描述

Md5Hsah 类的简单使用:


public class TestShiroMD5 {

    public static void main(String[] args) {

        // 使用 MD5

        Md5Hash md5Hash = new Md5Hash("1234");

        System.out.println(md5Hash.toHex());

        // 81dc9bdb52d04dc20036dbd8313ed055



        // 使用 Md5 + salt

        Md5Hash md5Hash1 = new Md5Hash("1234", "X0*7ps");

        System.out.println(md5Hash1);

        // 6029a2a0be49f2d4f21941c8ae2cea0c



        // 使用 Md5 + salt + hash 散列

        Md5Hash md5Hash2 = new Md5Hash("1234", "X0*7ps", 1024);

        System.out.println(md5Hash2.toHex());

        // 67cdf0cac7bdd508f560ef7965e8934c

    }

} 

自定义 md5 + salt 的 Realm 并验证

自定义 Realm 类:


/**

 * 自定义md5+salt realm

 */

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 ("zhenyu".equals(principal)) {

            String password = "6029a2a0be49f2d4f21941c8ae2cea0c";

            String salt = "X0*7ps";

            return new SimpleAuthenticationInfo(principal, password,

                    ByteSource.Util.bytes(salt), this.getName());

        }

        return null;

    }

} 

public class TestCustomerRealmAuthenticator {

public static void main(String[] args) {

    // 创建securityManager

    DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();

    // 设置为自定义realm获取认证数据

    CustomerMd5Realm customerMd5Realm = new CustomerMd5Realm();

    // 设置md5加密

    HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();

    credentialsMatcher.setHashAlgorithmName("MD5"); // 设置使用的加密算法

    credentialsMatcher.setHashIterations(1024); // 设置散列次数

    customerMd5Realm.setCredentialsMatcher(credentialsMatcher);

    defaultSecurityManager.setRealm(customerMd5Realm);

    // 安装工具类中设置默认安全管理器

    SecurityUtils.setSecurityManager(defaultSecurityManager);

    // 获取主体对象

    Subject subject = SecurityUtils.getSubject();

    // 创建token令牌

    UsernamePasswordToken token = new UsernamePasswordToken("zhenyu", "1234");

    try {

        subject.login(token);//用户登录

        System.out.println("登录成功~~");

    } catch (UnknownAccountException e) {

        e.printStackTrace();

        System.out.println("用户名错误!!");

    } catch (IncorrectCredentialsException e) {

        e.printStackTrace();

        System.out.println("密码错误!!!");

最后

CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】

        e.printStackTrace();

        System.out.println("用户名错误!!");

    } catch (IncorrectCredentialsException e) {

        e.printStackTrace();

        System.out.println("密码错误!!!");

最后

CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】

[外链图片转存中…(img-IGXaQlAn-1630839661986)]

[外链图片转存中…(img-5AqgXYS0-1630839661987)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值