• Shiro笔记(四)编码/加密


    Shiro笔记(四)编码/加密

    一、编码和解码

     1     //base64编码、解码
     2     @Test
     3     public void testBase64(){
     4         String str="tang";
     5         byte[] encode = Base64.encode(str.getBytes());
     6         System.out.println("Encode result:"+encode);
     7         System.out.println("The decode result:"+Base64.decodeToString(encode));
     8     }
     9 
    10     //16进制字符串编码,解码
    11     @Test
    12     public void testHex(){
    13         String str="Java";
    14         char[] encode = Hex.encode(str.getBytes());
    15         System.out.println("encode result:"+encode);
    16         System.out.println("decode result:"+new String(Hex.decode(encode)));
    17     }

    二、散列算法

    散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5,SHA等。

     1     //MD5算法
     2     @Test
     3     public void testMD5(){
     4         String str="king";
     5         String salt="salt1";
     6         String s = new Md5Hash(str, salt).toString();
     7         System.out.println("MD5 code: "+s);
     8     }
     9 
    10     //SHA算法
    11     @Test
    12     public void testSHA(){
    13         String str="king";
    14         String salt="salt1";
    15         String s = new Sha256Hash(str, salt).toString();
    16         System.out.println("SHA code: "+s);
    17     }

    三、PasswordService/CredentialMatcher

    Shiro 提供了 PasswordService CredentialsMatcher 用于提供加密密码及验证密码服务。

     1 public interface PasswordService {
     2 
     3     //输入明文密码得到密文密码
     4     String encryptPassword(Object plaintextPassword) throws IllegalArgumentException;
     5 
     6     /**
     7      * @param submittedPlaintext a raw/plaintext password submitted by an end user/Subject.
     8      * @param encrypted          the previously encrypted password known to be associated with an account.
     9      *                           This value is expected to have been previously generated from the
    10      *                           {@link #encryptPassword(Object) encryptPassword} method (typically
    11      *                           when the account is created or the account's password is reset).
    12      * @return {@code true} if the {@code submittedPlaintext} password matches the existing {@code saved} password,
    13      *         {@code false} otherwise.
    14      * @see ByteSource.Util#isCompatible(Object)
    15      */
    16     boolean passwordsMatch(Object submittedPlaintext, String encrypted);
    17 }
    1 public interface CredentialsMatcher {
    2 
    3     //匹配用户输入的 token 的凭证(未加密)与系统提供的凭证(已加密)
    4     boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info);
    5 
    6 }

    Shiro 默认提供了 PasswordService 实现 DefaultPasswordServiceCredentialsMatcher 实现
    PasswordMatcher HashedCredentialsMatcher(更强大)。

    应用实例:

     1 public class MyRealm extends AuthorizingRealm{
     2 
     3     private PasswordService passwordService;
     4 
     5     public void setPasswordService(PasswordService passwordService) {
     6         this.passwordService = passwordService;
     7     }
     8 
     9     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    10         return null;
    11     }
    12 
    13     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    14         return new SimpleAuthenticationInfo("tang",
    15                 passwordService.encryptPassword("123456"),getName());
    16     }
    17 }

    HashedCredentialsMatcher应用:

     1 public class MyRealm2 extends AuthorizingRealm {
     2 
     3     @Override
     4     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
     5         return null;
     6     }
     7 
     8     @Override
     9     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    10         String username = "liu"; //用户名及salt1
    11         String salt2 = "0072273a5d87322163795118fdd7c45e";
    12         String password = "be320beca57748ab9632c4121ccac0db"; //加密后的密码
    13         SimpleAuthenticationInfo ai = new SimpleAuthenticationInfo(username, password, getName());
    14         ai.setCredentialsSalt(ByteSource.Util.bytes(username+salt2)); //盐是用户名+随机数
    15         return ai;
    16     }
    17 }

    四、密码重试次数限制

    如在 1 个小时内密码最多重试 5 次,如果尝试次数超过 5 次就锁定 1 小时,1 小时后可再
    次重试,如果还是重试失败,可以锁定如 1 天,以此类推,防止密码被暴力破解。我们通
    过继承 HashedCredentialsMatcher,且使用 Ehcache 记录重试次数和超时时间。

     1 public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
     2 
     3     private Ehcache passwordRetryCache;
     4 
     5     public RetryLimitHashedCredentialsMatcher() {
     6         CacheManager cacheManager = CacheManager.newInstance(CacheManager.class.getClassLoader().getResource("ehcache.xml"));
     7         passwordRetryCache = cacheManager.getCache("passwordRetryCache");
     8     }
     9 
    10     @Override
    11     public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
    12         String username = (String)token.getPrincipal();
    13         //retry count + 1
    14         Element element = passwordRetryCache.get(username);
    15         if(element == null) {
    16             element = new Element(username , new AtomicInteger(0));
    17             passwordRetryCache.put(element);
    18         }
    19         AtomicInteger retryCount = (AtomicInteger)element.getObjectValue();
    20         if(retryCount.incrementAndGet() > 5) {
    21             //if retry count > 5 throw
    22             throw new ExcessiveAttemptsException();
    23         }
    24 
    25         boolean matches = super.doCredentialsMatch(token, info);
    26         if(matches) {
    27             //clear retry count
    28             passwordRetryCache.remove(username);
    29         }
    30         return matches;
    31     }
    32 }
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <ehcache name="es">
     3 
     4     <diskStore path="java.io.tmpdir"/>
     5 
     6 
     7 
     8     <!-- 登录记录缓存 锁定10分钟 -->
     9     <cache name="passwordRetryCache"
    10            maxEntriesLocalHeap="2000"
    11            eternal="false"
    12            timeToIdleSeconds="3600"
    13            timeToLiveSeconds="0"
    14            overflowToDisk="false"
    15            statistics="true">
    16     </cache>
    17 
    18 </ehcache>
    Simple is important!
  • 相关阅读:
    Linux下校验下载文件的完整性(MD5,SHA1,PGP)
    十六进制字节 & 十六进制转二进制
    session & cookie
    php与mysql的链接到底用mysql 还是mysqli,pdo
    php连接数据库时候的字符集设置
    Prepared statements(mysqli & pdo)
    shell脚本中执行mysql命令
    centos系统字符编码问题
    实用crontab命令
    shell获取用户输入
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/7677219.html
Copyright © 2020-2023  润新知