shiro-散列算法

认识md5

md5是一种加密算法,保护数据安全(现被证实并不怎么安全),shiro中提供了md5加密算法
salt表示加盐,通过加盐的方式能够进一步提高数据的安全性,所以在数据库users表设计的时候,除了id、username、password之外,还有一列password_salt

//md5加密
		Md5Hash hash=new Md5Hash("123");
		System.out.println(hash.toString());
		//md5加盐
		hash=new Md5Hash("123","wit");
		System.out.println(hash.toString());
		//md5加盐 散列两次,散列次数越多,密码越安全
		hash=new Md5Hash("123","wit",2);
		System.out.println(hash.toString());
		hash=new Md5Hash("456","wit",2);
		System.out.println(hash.toString());
		

使用md5呢,首先要保证数据库中的密码是(已经用工具)加密过的
在这里插入图片描述

自定义的realm

从数据库拿到数据user(id、username、password、password_salt)对象后,下边这行代码传给shiro,shiro就知道需要数据是加密过的,还有一些参数,比如散列次数,加密方式,就需要对realm进行配置

SimpleAuthenticationInfo(username,password,ByteSource.Util.bytes(salt),getName());
package cn.wit.realm;

import java.beans.PropertyVetoException;


import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import cn.wit.users.Users;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.PreparedStatement;

public class UserRealm extends AuthorizingRealm{
    
    
	@Override
	public String getName() {
    
    
		// TODO Auto-generated method stub
		return "uesrRealm";
	}
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
    
    
		return null;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken taken) throws AuthenticationException {
    
    
			String username=(String) taken.getPrincipal();
			Users users=null;
			Connection conn=null;
	        PreparedStatement ps=null;
	        ResultSet rs=null;
	        ComboPooledDataSource cpds=null;
	        try {
    
    
	          //c3p0获取数据库连接conn
	    		cpds= new ComboPooledDataSource();
	    		cpds.setDriverClass("com.mysql.jdbc.Driver");
	    		cpds.setJdbcUrl("jdbc:mysql://localhost:3306/login");
	    		cpds.setUser("root");
	    		cpds.setPassword("wityy");
	    		conn = cpds.getConnection();
	            
	            String sql="select *from users where username=?";
	            ps= conn.prepareStatement(sql);
	            ps.setObject(1,username);
	            rs=ps.executeQuery();
	            while(rs.next()){
    
    
	            	users=new Users();
	            	users.setId(rs.getInt("id"));
	            	users.setUsername(rs.getString("username"));
	            	users.setPassword(rs.getString("password"));
	            	users.setPassword_salt(rs.getString("password_salt"));
	            }
	        } catch (SQLException e) {
    
    
	            e.printStackTrace();
	        } catch (PropertyVetoException e) {
    
    
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally {
    
    
	            try {
    
    
	            	if(rs!=null){
    
    
	            		rs.close();
	            	}
	            } catch (SQLException e) {
    
    
	                e.printStackTrace();
	            }
	            try {
    
    
	            	if(ps!=null){
    
    
	            		ps.close();
	            	}
	            } catch (SQLException e) {
    
    
	                e.printStackTrace();
	            }
	            try {
    
    
	            	if(conn!=null){
    
    
	            		conn.close();
	            	}
	            } catch (SQLException e) {
    
    
	                e.printStackTrace();
	            }
	        }
		
	      username=users.getUsername();
	      String password=users.getPassword();
	      String salt=users.getPassword_salt();
	      System.out.println(username);
	      System.out.println(password);
	      System.out.println(salt);
	      //从数据库中拿到的密码是经过加密的(并且加了盐),所以数据库中才设计盐这个属性,想要解密不仅要拿到密码,还要从数据库拿到盐
	      //除此之外,需要设置realm 告知shiro需要用md5的方式进行解密
	      SimpleAuthenticationInfo info=new 
	    		  SimpleAuthenticationInfo(username,password,ByteSource.Util.bytes(salt),getName());
		
		
		
		return info;
	}

	
}

ini

hashAlgorithmName表示加密方式,hashIterations表示散列次数,credentialsMatcher是关于设置加密的类,将其赋值给realm。对于加密的源码跟踪文章尾部有介绍

[main]
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=md5
credentialsMatcher.hashIterations=2

userRealm=cn.wit.realm.UserRealm
userRealm.credentialsMatcher=$credentialsMatcher
securityManager.realm=$userRealm

md5源码跟踪

从login进入源码,subject实现类DelegatingSubject,将自己和taken都给了SecurityManager,实现类为DefaultSecurityManager,该类login方法调用Authenticator的Authenticate方法,进入Authenticator,实现类为ModularRealmAuthenticator,里边有setRealms、setAuthenticationStrategy,可以进行 认证策略和realms的设置,进入Realm接口,在它的实现类AuthenticatingRealm里面有credentialsMatcher属性,表示加密
在这里插入图片描述
查看类层次,下边有不同的解密方式的实现类,

在这里插入图片描述
这些加密的方式都是继承的HashedCredentialsMatcher,下边的这个类的set方法,我们在ini中设置的正是这些属性,出于对salt信息的保护,所以设置ini只设置了加密方式和散列次数,将salt在自定义的realm中跟账号密码一起传递给shiro
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/WA_MC/article/details/113564487