Shiro-多Realm配置及认证策略

 认证策略

 用法

spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


	<!-- 配置SecurityManager -->
	<bean id="securityManager"
		class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="cacheManager" ref="cacheManager" />
		<!-- Single realm app. If you have multiple realms, use the 'realms' property 
			instead. -->
		<property name="sessionMode" value="native" />
		<!-- 这里是将多个Realm配置在实现了 AbstractAuthenticator 的org.apache.shiro.authc.pam.ModularRealmAuthenticator中 ,由ModularRealmAuthenticator进行认证-->
		<property name="authenticator" ref="authenticator"></property>
		<!-- <property name="realm" ref="jdbcRealm" /> -->
	</bean>

	<!-- 配置cacheManager
			需要加入ehcache的配置文件和jar包
	 -->
	<bean id="cacheManager"	class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
	</bean>


	<!-- 配置多reaml的认证器 -->
	<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
		<property name="realms">
			<list>
				<ref bean="jdbcRealm"/>
				<ref bean="secondRealm"/>
			</list>
		</property>
	</bean>

	<!-- Used by the SecurityManager to access security data (users, roles, 
		etc). Many other realm implementations can be used too (PropertiesRealm, 
		LdapRealm, etc. -->
	<!-- 直接使用实现了Realm接口的bean -->
	<bean id="jdbcRealm" class="com.atguigu.shiro.realms.ShiroRealm">
		<!-- 配置凭证匹配器 -->
		<property name="credentialsMatcher">
			<!-- shiro推荐直接使用 HashedCredentialsMatcher-->
			<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
				<property name="hashAlgorithmName" value="MD5"></property>
				<property name="hashIterations" value="1024"></property>
			</bean>
		</property>
	</bean>

	<bean id="secondRealm" class="com.atguigu.shiro.realms.SecondRealm">
		<!-- 配置凭证匹配器 -->
		<property name="credentialsMatcher">
			<!-- shiro推荐直接使用 HashedCredentialsMatcher-->
			<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
				<property name="hashAlgorithmName" value="SHA1"></property>
				<property name="hashIterations" value="1024"></property>
			</bean>
		</property>
	</bean>
	<!-- ========================================================= Shiro Spring-specific integration ========================================================= -->
	<!-- Post processor that automatically invokes init() and destroy() methods 
		for Spring-configured Shiro objects so you don't have to 1) specify an init-method 
		and destroy-method attributes for every bean definition and 2) even know 
		which Shiro objects require these methods to be called. -->
	<!-- 配置生命周期的后置处理器,自动调用spirng的IOC容器中shiro的方法 -->
	<bean id="lifecycleBeanPostProcessor"
		class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

	<!-- Enable Shiro Annotations for Spring-configured beans. Only run after 
		the lifecycleBeanProcessor has run: 
		启用shiro的生命周期注解,其依赖lifecycleBeanPostProcessor,所以在配置了lifecycleBeanPostProcessor之后才能生效	
	-->
	<bean
		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
		depends-on="lifecycleBeanPostProcessor" />
	<bean
		class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>

	<!--
		这里的id必须于web.xml文件中配置的DelegatingFilterProxy的filter-name一样
		若不一样则抛出NoSuchBeanDefinitionException 
		因为shiro会到spring的IOC容器中找shiroFilter对应的bean
		
		若不一致的话也可以在fileter的初始化参数中配置targetBeanName,将这里的shiroFilter换成targetBeanName的值就可以了
	-->
	<bean id="shiroFilter"
		class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login.jsp" />
		<property name="successUrl" value="/list.jsp" />
		<property name="unauthorizedUrl" value="/unauthorized.jsp" />
		<!-- 
			配置哪些页面需要保护
			以及访问页面的权限
			拦截器:(这里的url支持Ant风格模式)
			1).anon 可以被匿名访问
			2) .authc 需要认证才能访问
			3) .logout 登出过滤器
			这里的url优先匹配
		 -->
		<property name="filterChainDefinitions">
			<value>
				/login.jsp = anon
				/shiro/login = anon
				/shiro/logout = logout
				# everything else requires authentication:
				/** = authc
				
				/list.jsp = anon
			</value>
		</property>
	</bean>


</beans>

ShiroRealm.java

package com.atguigu.shiro.realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;

/**
 * 
 * @author Lee
 *
 */
public class ShiroRealm extends AuthenticatingRealm {

	private static final String MONSTER = "monster";
	private static final String UNKNOW = "unknow";
	private static final String ALGORITHM_NAME = "MD5";

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

		System.out.println("[First] doGetAuthenticationInfo");

		// 1、将AuthenticationToken转换为UsernamePasswordToken
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		// 2、从UsernamePasswordToken中获取username
		String username = upToken.getUsername();
		// char[] password = upToken.getPassword();
		// 3、从数据库中获取username对应的记录
		System.out.println("从数据库中查找" + username + "对应的记录");
		// 4、若用户不存在抛出UnknownAccountException异常
		if (UNKNOW.equals(username)) {
			throw new UnknownAccountException("用户不存在");
		}
		// 5、根据用户的信息决定是否抛出AuthenticationException异常
		if (MONSTER.equals(username)) {
			throw new LockedAccountException("用户被锁定");
		}
		// 6、根据用户情况,构建 AuthenticationInfo 对象并返回
		// 一下信息是从数据库中获取
		// 1)principal:认证的实体信息,可以是username,也可以是数据表对应的用户的实体类对象。
		Object principal = username;
		// 2) credentials:密码
		Object hashedCredentials = null; // "fc1709d0a95a6be30bc5926fdb7f22f4";
		if (username.equals("admin")) {
			hashedCredentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
		} else if (username.equals("user")) {
			hashedCredentials = "098d2c478e9c11555ce2823231e02ec1";
		}

		// 3) realmName:当前realm对象的name,调用父类的getName()方法获取
		String realmName = getName();
		// 比较密码是由AuthenticatingRealm的CredentialsMatcher进行比较的
		// 4) credentialsSalt:盐值.
		// 这里的ByteSource为接口,里面有内部类Util,方法中的字符串是唯一的字符串,这里使用username,username是用户的唯一标识

		// 唯一的字符串
		ByteSource credentialsSalt = ByteSource.Util.bytes(username);
		SimpleAuthenticationInfo info = null; // new SimpleAuthenticationInfo(principal, credentials, realmName);
		info = new SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realmName);
		return info;
	}

	public static void main(String[] args) {
		ByteSource credentialsSalt = ByteSource.Util.bytes("user");
		int hashIterations = 1024;
		String credentials = "123456";
		SimpleHash simpleHash = new SimpleHash(ALGORITHM_NAME, credentials, credentialsSalt, hashIterations);
		System.out.println(simpleHash);

	}

}

SecondRealm.java

package com.atguigu.shiro.realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;

/**
 * 
 * @author Lee
 *
 */
public class SecondRealm extends AuthenticatingRealm {

	private static final String MONSTER = "monster";
	private static final String UNKNOW = "unknow";
	private static final String ALGORITHM_NAME = "SHA1";

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

		System.out.println("[SecondRealm] doGetAuthenticationInfo");

		// 1、将AuthenticationToken转换为UsernamePasswordToken
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		// 2、从UsernamePasswordToken中获取username
		String username = upToken.getUsername();
		// char[] password = upToken.getPassword();
		// 3、从数据库中获取username对应的记录
		System.out.println("从数据库中查找" + username + "对应的记录");
		// 4、若用户不存在抛出UnknownAccountException异常
		if (UNKNOW.equals(username)) {
			throw new UnknownAccountException("用户不存在");
		}
		// 5、根据用户的信息决定是否抛出AuthenticationException异常
		if (MONSTER.equals(username)) {
			throw new LockedAccountException("用户被锁定");
		}
		// 6、根据用户情况,构建 AuthenticationInfo 对象并返回
		// 一下信息是从数据库中获取
		// 1)principal:认证的实体信息,可以是username,也可以是数据表对应的用户的实体类对象。
		Object principal = username;
		// 2) credentials:密码
		Object hashedCredentials = null; // "fc1709d0a95a6be30bc5926fdb7f22f4";
		if (username.equals("admin")) {
			hashedCredentials = "ce2f6417c7e1d32c1d81a797ee0b499f87c5de06--";
		} else if (username.equals("user")) {
			hashedCredentials = "073d4c3ae812935f23cb3f2a71943f49e082a718--";
		}

		// 3) realmName:当前realm对象的name,调用父类的getName()方法获取
		String realmName = getName();
		// 比较密码是由AuthenticatingRealm的CredentialsMatcher进行比较的
		// 4) credentialsSalt:盐值.
		// 这里的ByteSource为接口,里面有内部类Util,方法中的字符串是唯一的字符串,这里使用username,username是用户的唯一标识

		// 唯一的字符串
		ByteSource credentialsSalt = ByteSource.Util.bytes(username);
		SimpleAuthenticationInfo info = null; // new SimpleAuthenticationInfo(principal, credentials, realmName);
		info = new SimpleAuthenticationInfo("SecondRealm", hashedCredentials, credentialsSalt, realmName);
		return info;
	}

	public static void main(String[] args) {
		ByteSource credentialsSalt = ByteSource.Util.bytes("admin");
		int hashIterations = 1024;
		String credentials = "123456";
		SimpleHash simpleHash = new SimpleHash(ALGORITHM_NAME, credentials, credentialsSalt, hashIterations);
		System.out.println(simpleHash);

	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值