天天看點

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

一、Shiro介紹:

1、什麼是shiro:

(1)shiro是apache的一個開源架構,是一個權限管理的架構,實作使用者認證、使用者授權。

(2)spring中有spring security,是一個權限架構,但是它和spring依賴過于緊密,沒有shiro使用簡單。shiro不依賴于spring,shiro不僅可以實作 web應用的權限管理,還可以實作c/s系統,分布式系統權限管理,shiro屬于輕量架構,越來越多企業項目開始使用shiro。

(3)使用shiro實作系統 的權限管理,有效提高開發效率,進而降低開發成本。

2、shiro架構:

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

(1)subject:主體,可以是使用者也可以是程式,主體要通路系統,系統需要對主體進行認證、授權。

(2)securityManager:安全管理器,主體進行認證和授權都 是通過securityManager進行。

(3)authenticator:認證器,主體進行認證最終通過authenticator進行的。

(4)authorizer:授權器,主體進行授權最終通過authorizer進行的。

(5)sessionManager:web應用中一般是用web容器對session進行管理,shiro也提供一套session管理的方式。

(6)SessionDao:  通過SessionDao管理session資料,針對個性化的session資料存儲需要使用sessionDao。

(7)cache Manager:緩存管理器,主要對session和授權資料進行緩存,比如将授權資料通過cacheManager進行緩存管理,和ehcache整合對緩存資料進行管理。

(8)realm:域,領域,相當于資料源,通過realm存取認證、授權相關資料。在realm中存儲授權和認證的邏輯。

(9)cryptography:密碼管理,提供了一套加密/解密的元件,友善開發。比如提供常用的散列、加/解密等功能。比如 md5雜湊演算法。

3、相關jar包依賴:

與其它java開源架構類似,将shiro的jar包加入項目就可以使用shiro提供的功能了。shiro-core是核心包必須選用,還提供了與web整合的shiro-web、與spring整合的shiro-spring、與任務排程quartz整合的shiro-quartz等

<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>1.4.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-web</artifactId>
			<version>1.4.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-ehcache</artifactId>
			<version>1.4.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-quartz</artifactId>
			<version>1.4.0</version>
		</dependency>               

也可以通過引入shiro-all包括shiro所有的包:

<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-all</artifactId>
	<version>1.4.0</version>
</dependency>           

二、Shiro認證入門程式搭建:

1、shiro認證流程:

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

2、導入jar包依賴:shiro-core.jar

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

3、工程結構:

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

4、編寫shiro-first.ini配置檔案:

通過此配置檔案建立securityManager工廠。

#對使用者資訊進行配置
[users]
#使用者賬戶和密碼
zhangsan=111111
lisi=222222           

5、Authentication類:

//shiro入門程式測試類:
public class Authentication {

	//使用者登陸和退出測試
	@Test
	public void testLogin(){
		//1、建立securityManager工廠,通過ini配置檔案建立securityManager工廠
		Factory<SecurityManager> factory=
				new IniSecurityManagerFactory("classpath:shiro-first.ini");
		//2、建立securityManager
		SecurityManager securityManager=factory.getInstance();
		//3、将SecurityManager設定在目前運作環境中
		SecurityUtils.setSecurityManager(securityManager);
		//4、從SecurityUtils裡面 建立一個subject;
		Subject subject=SecurityUtils.getSubject();
		
		//5、在認證送出前準備token(令牌)
		UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","111111");
		
		try{
			//6、執行認證送出;
			subject.login(token);
		}catch (AuthenticationException  e) {
			e.printStackTrace();
		}
		
		//7、是否認證通過
		boolean isAuthenticated = subject.isAuthenticated();
		System.out.println("是否認證通過:"+isAuthenticated);
	
		//8、退出操作
		subject.logout();
		isAuthenticated = subject.isAuthenticated();
		System.out.println("是否認證通過:"+isAuthenticated);
	}
}           

6、運作結果:

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

至此,一個簡單的shiro入門程式就搭建完成了。

三、shiro的執行流程:

1、通過ini配置檔案建立securityManager;

2、調用subject.login方法主體送出認證,送出的token;

3、securityManager進行認證,securityManager最終由ModularRealmAuthenticator進行認證;

4、ModularRealmAuthenticator調用IniRealm(給realm傳入token) 去ini配置檔案中查詢使用者資訊;

5、IniRealm根據輸入的token(UsernamePasswordToken)從 shiro-first.ini查詢使用者資訊,根據賬号查詢使用者資訊(賬号和密碼):

(1)如果查詢到使用者資訊,就給ModularRealmAuthenticator傳回使用者資訊(賬号和密碼)

(2)如果查詢不到,就給ModularRealmAuthenticator傳回null

6、ModularRealmAuthenticator接收IniRealm傳回Authentication認證資訊

(1)如果傳回的認證資訊是null,ModularRealmAuthenticator抛出異常(org.apache.shiro.authc.UnknownAccountException)

(2)如果傳回的認證資訊不是null(說明inirealm找到了使用者),對IniRealm傳回使用者密碼 (在ini檔案中存在)和 token中的密碼 進行對比,如果不一緻抛出異常(org.apache.shiro.authc.IncorrectCredentialsException)

小結:

ModularRealmAuthenticator的作用是進行認證,需要調用realm查詢使用者資訊(在資料庫中存在使用者資訊),

ModularRealmAuthenticator進行密碼對比(認證過程)。

realm:需要根據token中的身份資訊去查詢資料庫(入門程式使用ini配置檔案),如果查到使用者傳回認證資訊,如果查詢不到傳回null。

四、自定義Reaml進行使用者認證:

實際開發需要realm從資料庫中查詢使用者資訊。

1、繼承realm接口:

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

2、自定義realm的示例:

工程結構:

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

3、自定義realm:

//自定義的Realm,需要繼承AuthorizingRealm
public class CustomRealm extends AuthorizingRealm{

	// 設定realm的名稱
	@Override
	public void setName(String name) {
		super.setName("customRealm");
	}

	// 用于認證
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {

		// token是使用者輸入的
		// 第一步從token中取出身份資訊
		String userCode = (String) token.getPrincipal();

		// 第二步:根據使用者輸入的userCode從資料庫查詢
		// ....
		// 如果查詢不到傳回null
		//這個例子中假設資料庫中使用者賬号是zhangsansan
		if(!userCode.equals("zhangsan")){//
			return null;
		}
		// 模拟從資料庫查詢到密碼是111111
		String password = "111111";

		// 如果查詢到傳回認證資訊AuthenticationInfo
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
				userCode, password, this.getName());

		return simpleAuthenticationInfo;
	}

	// 用于授權
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		// TODO Auto-generated method stub
		return null;
	}
}           

4、配置realm:

需要在shiro-realm.ini配置realm注入到securityManager中:

[main]
#自定義的realm
customRealm=com.zwp.shiro.realm.CustomRealm
#将realm設定到securityManager,相當于spring中的注入
securityManager.realms=$customRealm           

5、測試:

@Test
	public void testCustomRealm() {
		//1、建立securityManager工廠,通過ini配置檔案建立securityManager工廠
		Factory<SecurityManager> factory=
				new IniSecurityManagerFactory("classpath:shiro-realm.ini");
		//2、建立securityManager
		SecurityManager securityManager=factory.getInstance();
		//3、将SecurityManager設定在目前運作環境中
		SecurityUtils.setSecurityManager(securityManager);
		//4、從SecurityUtils裡面 建立一個subject;
		Subject subject=SecurityUtils.getSubject();
		
		//5、在認證送出前準備token(令牌)
		UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","111111");
		
		try{
			//6、執行認證送出;
			subject.login(token);
		}catch (AuthenticationException  e) {
			e.printStackTrace();
		}
		
		//7、是否認證通過
		boolean isAuthenticated = subject.isAuthenticated();
		System.out.println("是否認證通過:"+isAuthenticated);
	
		//8、退出操作
		subject.logout();
		isAuthenticated = subject.isAuthenticated();
		System.out.println("是否認證通過:"+isAuthenticated);
	}           

6、測試結果:

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

至此,Realm的配置就完成了。

五、Shiro的MD5加密算法:

1、雜湊演算法:

在項目中,通常需要對密碼進行散列,常用的有MD5、SHA。

(1)對md5密碼,如果知道散列後的值可以通過窮舉算法,得到md5密碼對應的明文。是以,建議對md5進行散列時加salt(鹽),進行加密相當于對原始密碼+鹽進行散列。

(2)正常使用時散列方法:

在程式中對原始密碼+鹽進行散列,将散列值存儲到資料庫中,并且還要将鹽也要存儲在資料庫中。

(3)如果進行密碼對比時,使用相同方法,将原始密碼+鹽進行散列,進行比對。

2、MD5散列測試程式:

public class MD5Test {
	public static void main(String[] args) {
		//原始 密碼 
		String source = "111111";
		//鹽
		String salt = "qwerty";
		//散列次數
		int hashIterations = 2;
		//上邊散列1次:f3694f162729b7d0254c6e40260bf15c
		//上邊散列2次:36f2dfa24d0a9fa97276abbe13e596fc
		
		//構造方法中:
		//第一個參數:明文,原始密碼 
		//第二個參數:鹽,通過使用随機數
		//第三個參數:散列的次數,比如散列兩次,相當 于md5(md5(''))
		Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations);
		
		String password_md5 =  md5Hash.toString();
		System.out.println(password_md5);
		//第一個參數:雜湊演算法 
		SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations);
		System.out.println(simpleHash.toString());
	}
}           

3、自定義realm支援雜湊演算法:

需求:實際開發時,realm要進行MD5值(明文散列後的值)的對比;

(1)項目結構:

Shiro架構:Shiro簡介、登陸認證入門程式、認證執行流程、使用自定義Realm進行登陸認證、Shiro的MD5雜湊演算法

(2)建立realm:(CustomRealmMd5.java)

//自定義realm支援雜湊演算法:
public class CustomRealmMd5 extends AuthorizingRealm {
	// 設定realm的名稱
	@Override
	public void setName(String name) {
		super.setName("customRealmMd5");
	}
	
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// token是使用者輸入的
		// 第一步從token中取出身份資訊
		String userCode = (String) token.getPrincipal();

		// 第二步:根據使用者輸入的userCode從資料庫查詢
		// ....
		// 如果查詢不到傳回null
		// 資料庫中使用者賬号是zhangsansan
		if(!userCode.equals("zhangsan")){
			 return null; 
		 }

		// 模拟從資料庫查詢到密碼,散列值
		String password = "13f79dafcbbedc313273e2b891ac84d3";
		// 從資料庫擷取salt
		String salt = "qwerty";
		//上邊散列值和鹽對應的明文:123456 散列次數2

		// 如果查詢到傳回認證資訊AuthenticationInfo
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
				userCode, password, ByteSource.Util.bytes(salt), this.getName());

		return simpleAuthenticationInfo;
	}
	
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		return null;
	}
}           

(3)在realm的ini檔案中配置憑證比對器:

[main]
#定義憑證比對器:
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#雜湊演算法:
credentialsMatcher.hashAlgorithmName=md5
#散列次數:
credentialsMatcher.hashIterations=2

#将憑證比對器設定到realm
customRealm=com.zwp.shiro.realm.CustomRealmMd5
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm           

(4)測試類:

//自定義realm支援雜湊演算法測試:
	@Test
	public void testCustomRealmMd5() {
		//1、建立securityManager工廠,通過ini配置檔案建立securityManager工廠
		Factory<SecurityManager> factory=
				new IniSecurityManagerFactory("classpath:shiro-realm-md5.ini");
		//2、建立securityManager
		SecurityManager securityManager=factory.getInstance();
		//3、将SecurityManager設定在目前運作環境中
		SecurityUtils.setSecurityManager(securityManager);
		//4、從SecurityUtils裡面 建立一個subject;
		Subject subject=SecurityUtils.getSubject();
		
		//5、在認證送出前準備token(令牌)
		UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123456");
		
		try{
			//6、執行認證送出;
			subject.login(token);
		}catch (AuthenticationException  e) {
			e.printStackTrace();
		}
		
		//7、是否認證通過
		boolean isAuthenticated = subject.isAuthenticated();
		System.out.println("是否認證通過:"+isAuthenticated);
	
		//8、退出操作
		subject.logout();
		isAuthenticated = subject.isAuthenticated();
		System.out.println("是否認證通過:"+isAuthenticated);
	}           

至此,自定義realm支援雜湊演算法的就完成了。

繼續閱讀