1. 程式人生 > >spring整合shiro實現登入認證自定義驗證功能(認證採用國密SM4演算法)

spring整合shiro實現登入認證自定義驗證功能(認證採用國密SM4演算法)

        公司在建專案採用的開發框架為spring+springMvc+hibernate,安全框架採用的是shiro,安全認證沿用了shiro自帶的HashedCredentialsMatcher,現客戶(國企)要求使用者密碼必須採用國密SM4演算法進行加密,因此需對安全認證模組進行改造。

1、新建一個自定義的適用於SMA4安全認證匹配類:

public class SM4CredentialsMatcher extends SimpleCredentialsMatcher {

	protected UserService userService;

	@Override
	public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		User user = userService.findByLoginName(token.getUsername());
		String salt = "";
		if (user != null) {
			if ("disabled".equals(user.getStatus())) {
				throw new DisabledAccountException();
			}

			salt = user.getSalt();
		}
		Object tokenCredentials = SM4Util.encrypt(String.valueOf(token.getPassword()), salt);
		Object accountCredentials = getCredentials(info);
		// 將密碼加密與系統加密後的密碼校驗,內容一致就返回true,不一致就返回false
		return equals(tokenCredentials, accountCredentials);
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

}

2、修改自定義Realm類,重寫兩個方法:initCredentialsMatcher和assertCredentialsMatch

public class ShiroDbRealm extends AuthorizingRealm {

	protected UserService userService;

	protected RoleService roleService;
	
	protected SM4CredentialsMatcher sm4CredentialsMatcher;

	/**
	 * 認證回撥函式,登入時呼叫.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		User user = userService.findByLoginName(token.getUsername());
		if (user != null) {
			if ("disabled".equals(user.getStatus())) {
				throw new DisabledAccountException();
			}

			byte[] salt = Encodes.decodeHex(user.getSalt());
			return new SimpleAuthenticationInfo(new ShiroUser(
					user.getLoginName(), user.getName(), user.getId()),
					user.getPassword(), ByteSource.Util.bytes(salt), getName());
		} else {
			return null;
		}
	}

	/**
	 * 授權查詢回撥函式, 進行鑑權但快取中無使用者的授權資訊時呼叫.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
		// User user = userService.findByLoginName(shiroUser.getLoginName());
		List<Role> roles = this.userService
				.findRolesByUserId(shiroUser.getId());

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		for (Role role : roles) {
			// 基於Role的許可權資訊
			info.addRole(role.getCode());
		}
		info.addStringPermissions(this.userService
				.findUserPermissions(shiroUser.getId()));
		return info;
	}

	/**
	 * 更新使用者授權資訊快取.
	 */
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(
				principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有使用者授權資訊快取.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}

	
	@PostConstruct
	public void initCredentialsMatcher() {
		//註釋掉原來的匹配器程式碼
		//HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(
		// userService.HASH_ALGORITHM);
		// matcher.setHashIterations(userService.HASH_INTERATIONS);
		// setCredentialsMatcher(matcher);
		//設定自定義的安全認證匹配器,注意此處最好將匹配器採用注入的方式設定,若採用new的方式話,在匹配器中將無法使用spring視窗中的其他元件
		setCredentialsMatcher(sm4CredentialsMatcher);
	}

	/**
	 * 認證密碼匹配呼叫方法
	 * 
	 * @param authcToken
	 * @param info
	 * @throws AuthenticationException
	 */
	@Override
	protected void assertCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info)
			throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		super.assertCredentialsMatch(token, info);
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public void setSm4CredentialsMatcher(SM4CredentialsMatcher sm4CredentialsMatcher) {
		this.sm4CredentialsMatcher = sm4CredentialsMatcher;
	}



3、修改spring有關shiro的配置

	<description>Shiro安全配置</description>

	<!-- 單realm配置 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="adminRealm" />
		<property name="cacheManager" ref="shiroEhcacheManager" />
	</bean>

	<bean id="adminRealm" class="cn.company.framwork.sys.service.ShiroDbRealm"
		depends-on="userRepository,roleRepository">
		<property name="userService" ref="userService" />
		<!-- 將“安全認證匹配器”注入自定義的Realm中,用於初始化安全認證匹配器 -->
		<property name="sm4CredentialsMatcher" ref="sm4CredentialsMatcher" />
	</bean>
	
	<!-- 本次改造新增的 安全認證匹配器  -->
	<bean id="sm4CredentialsMatcher" class="cn.company.framwork.sys.service.SM4CredentialsMatcher" depends-on="userRepository">
		<property name="userService" ref="userService" />
	</bean>

4、改造完畢,剩下新建使用者時也採用國密SM4演算法加密儲存資料,可以進行系統登入測試了!