【Shiro】shiro加密

⽤戶的密碼是不允許明⽂存儲的,因爲⼀旦數據泄露,⽤戶的隱私信息會完全暴露。所以密碼必須結果加密,⽣成密⽂,然後數據庫中只存儲⽤戶的密碼的密⽂。

在加密過程中需要使⽤到⼀些"不可逆加密",如 md5,sha等
所謂不可逆是指:

加密函數A, 明⽂ “abc”,

A("abc") = "密⽂"

不能通過 “密⽂” 反推出 “abc”,即使密⽂泄露密碼仍然安全。

1. shiro加密介紹

shiro⽀持hash(散列)加密,常見的如 md5, sha等

  • 基本加密過程
    md5(明⽂),sha(明⽂) 得到明⽂的密⽂,但明⽂可能⽐較簡單,導致密⽂容易被破解。

  • 加鹽加密過程
    系統⽣成⼀個隨機salt=“xxxxxx”, md5(明⽂+salt) ,sha(明⽂+salt),則提升了密⽂的複雜度。

  • 加鹽多次迭代加密過程
    如果迭代次數爲2,則加密2次: md5(明⽂+salt)=密⽂a , md5(密⽂a+salt)=最終密⽂
    sha(明⽂+salt)=密⽂a , sha(密⽂a+salt)=最終密⽂
    則進⼀步提升了密⽂的複雜度,和被破解的難度。

加密過程中建議使⽤salt,並指定迭代次數,迭代次數的建議值1000+

  • 實例代碼:
String password="abc";//密碼明⽂
String salt=UUID.randomUUID().toString();//鹽
Integer iter = 1000;//迭代次數
String pwd = new Md5Hash(password, salt,iter).toString(); //md5加密
String pwd = new Md5Hash(password, salt, iter).toBase64(); //加密後轉base64
String pwd = new Sha256Hash(password, salt, iter).toString();//sha256加密
String pwd = new Sha256Hash(password, salt, iter).toBase64();//加密後轉base64
String pwd = new Sha512Hash(password, salt, iter).toString();//sha256加密
String pwd = new Sha512Hash(password, salt, iter).toBase64()//加密後轉base64

2. 加密

增加⽤戶,或修改⽤戶密碼時,涉及到密碼的加密

在註冊⽤戶的業務中,對⽤戶提交的密碼加密即可。
注意:我們需要在用戶表中加⼀列【 salt varchar(50) 】,⽤於存儲每個⽤戶的鹽(即隨機字符串)。

class UserServiceImpl implements UserService{
    @Autowired
    private UserDAO userDAO;
    public void createUser(User user){
        user.setSalt(UUID.randomUUID().toString());//設置隨機鹽
        //設置加密屬性:sha256算法,隨機鹽,迭代1000次
        Sha256Hash sha256Hash = new Sha256Hash(user.getPassword(),user.getSalt(),1000);
        //將⽤戶信息 (包括密碼的密⽂ 和 鹽) 存⼊數據庫
        user.setPassword(sha256Hash.toBase64());//密⽂採⽤base64格式化
        userDAO.createUser(user);
    }
}

3. 密碼比對

在登錄認證身份的時候,我們需要將登錄的密碼與正確的密碼進行比對,所以我們只需要將登錄用的密碼加入相同的鹽,並進行相同次數的迭代,最後進行比對就行了。

在shiro中,我們只需要聲明加密方式,加入的鹽,以及次數即可。

首先指定比對器

[main]
...
#聲明密碼⽐對器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=sha-256
credentialsMatcher.hashIterations=1000
# true=hex格式 false=base64格式
credentialsMatcher.storedCredentialsHexEncoded=false
#⽐對器關聯給realm,則realm中對⽤戶做身份認證時,可以使⽤加密⽐對器,對密⽂做⽐對
realm1 = com.siyi.realm.MyRealm
realm1.credentialsMatcher=$credentialsMatcher
#realm關聯給securityManager
securityManager.realms=$realm1

4. 更改自定義Realm

通過上面的配置我們很容易可以看出還缺少鹽的加入。而我們的salt本身就是隨機的所以不可能寫在配置文件中。所以我們將在程序中從數據庫中獲取鹽,並加入到認證方法中。

doGetAuthenticationInfo⽅法的返回值需要做修改。

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws
    AuthenticationException {
    String username = (String) token.getPrincipal();
    UserService userService =
        (UserService)ContextLoader.getCurrentWebApplicationContext().getBean("userService");
    User user = userService.queryUser(username);
    System.out.println("user:"+user);
    if(user==null){
        System.out.println("⽤戶不存在");
        throw new UnknownAccountException("username:"+username+"不存在");
    }
    //以上邏輯不變
    //在最後返回⽤戶認證info時,添加⼀個屬性:ByteSource.Util.bytes(user.getSalt()) = 鹽
    //⽤於密碼⽐對
    return new SimpleAuthenticationInfo(user.getUsername(),
                                        user.getPassword(),
                                        ByteSource.Util.bytes(user.getSalt()),
                                        getName());
}

這樣,可以進⾏註冊,註冊中已經會加密密碼。
然後登陸認證身份,認證時realm會調⽤⽐對器⽐對密⽂。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章