zoukankan      html  css  js  c++  java
  • 【Shiro】07 散列算法 & 凭证配置

    【散列算法概述】

    用于生成数据的摘要信息,不可逆算法,用于存储密码或者密文数据。

    常见散列算法类型:MD5、SHA

    一般进行散列时提供一个”盐“,即系统知道的”干扰数据“

    这样生成的密文更加难以被破解

    【盐?】

    加盐加密是一种对系统登录口令的加密方式,它实现的方式是将每一个口令跟一个n位随机数相关联,这个n位随机数叫做”盐“(salt)。

    加盐加密是一种对系统登录口令的加密方式,它实现的方式是将每一个口令同一个叫做”盐“(salt)的n位随机数相关联。

    无论何时只要口令改变,随机数就改变。

    随机数以未加密的方式存放在口令文件中,这样每个人都可以读。

    不再只保存加密过的口令,而是先将口令和随机数连接起来然后一同加密,加密后的结果放在口令文件中。

    演示案例:

    MD5加密

        @Test
        public void calcTest() {
            String source = "123456";
            
            Md5Hash hash1 = new Md5Hash(source);
            System.out.println("使用MD5加密后的结果:"+hash1.toString());
    
            Md5Hash hash2 = new Md5Hash(source, "北京武汉");
            System.out.println("使用MD5加密并加盐后的结果:"+hash2.toString());
            
            Md5Hash hash3 = new Md5Hash(source, "北京武汉", 2); // 一般两次就够了
            System.out.println("使用MD5加密加盐并散列两次后的结果:"+hash3.toString());
        }

    结果:

    使用MD5加密后的结果:e10adc3949ba59abbe56e057f20f883e
    使用MD5加密并加盐后的结果:19a45a53e8924a742f77183b8878a5fb
    使用MD5加密加盐并散列两次后的结果:b4f48723743cc5bfa7c1716296703ce1
    
    Process finished with exit code 0

    封装的加密工具类:

    public class EncryptionUtil {
    
        private EncryptionUtil(){}
    
        /**
         * MD5加密
         * 对秘密明文加密
         * @param plaintext 密码明文
         * @param salt ”盐“
         * @param hashFrequency 散列次数
         * @return 密文
         */
        public static String md5Encryption(String plaintext, Object salt, Integer hashFrequency) {
            return new Md5Hash(plaintext, salt, hashFrequency).toString();
        }
    
        /**
         * SHA1加密
         * @param plaintext 密码明文
         * @param salt ”盐“
         * @param hashFrequency 散列次数
         * @return 密文
         */
        public static String sha1Encryption(String plaintext, Object salt, Integer hashFrequency) {
            return new Sha1Hash(plaintext, salt, hashFrequency).toString();
        }
    }

    【凭证加密配置】

    方案一,在自定义Realm类的构造器中实现:

        public UserRealm() {
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
            hashedCredentialsMatcher.setHashAlgorithmName("md5"); // 指定加密算法名称
            hashedCredentialsMatcher.setHashIterations(2); // 指定散列次数
            this.setCredentialsMatcher(hashedCredentialsMatcher);
        }

    方案二,在shiro.ini文件中配置:

    [main]
    
    # 配置凭证匹配器
    credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
    credentialsMatcher.hashAlgorithmName=md5
    credentialsMatcher.hashIterations=2
    
    # 自定义Realm对象
    userRealm = cn.echo42.shiro.realm.userRealm
    userRealm.credentialsMatcher = $credentialsMatcher
    
    # 安全管理器
    securityManager=org.apache.shiro.mgt.DefaultSecurityManager
    securityManager.realm=$userRealm

    方法三,在业务程序中配置:

    就是把方案一放在外面处理了

        @Test
        public void testSample() {
            log.info("My First Apache Shiro Application");
    
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
    
            UserRealm userRealm = new UserRealm();
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
            hashedCredentialsMatcher.setHashAlgorithmName("md5");
            hashedCredentialsMatcher.setHashIterations(2);
            userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
    
            defaultSecurityManager.setRealm(userRealm);
    
    
            SecurityUtils.setSecurityManager(defaultSecurityManager);
    
            Subject subject = SecurityUtils.getSubject();
            AuthenticationToken userToken = new UsernamePasswordToken(username,password);
            subject.login(userToken);
        }

    其次,对应的也需要更改认证信息对象(UserRealm):

        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
            // 通过提交的令牌获取信息(用户名称?)
            String principal = authenticationToken.getPrincipal().toString();
    
            // 或者是业务层调取记录对象用来验证 User user=userService.queryUserByUserName(username);
    
            // 如果这里从数据库获取的用户名核对成功 返回一个简单的验证结果对象               // 用户名,令牌凭证(就是密码),和这个类的限定名
            if ("username".equals(principal)) // return new SimpleAuthenticationInfo(principal, authenticationToken.getCredentials(), this.getName());
            return new SimpleAuthenticationInfo(
                    principal, // 任意对象
                    authenticationToken.getCredentials(), // 从数据库返回的密文密码
                    ByteSource.Util.bytes("使用的盐,这里可以动态也可以是这种静态的"),
                    getName() // 类名
            );
            // 否则返回空,表明查不到
            return null;
        }
  • 相关阅读:
    转载:QTableView中嵌入可视化组件
    pyqt声音输入
    pyqt二进制和图片的转换
    LeetCode(92):反转链表 II
    LeetCode(91):解码方法
    LeetCode(90):子集 II
    LeetCode(89):格雷编码
    LeetCode(88):合并两个有序数组
    LeetCode(87):扰乱字符串
    LeetCode(86):分隔链表
  • 原文地址:https://www.cnblogs.com/mindzone/p/13416467.html
Copyright © 2011-2022 走看看