欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Shiro基于Spring的实现

程序员文章站 2022-06-04 15:30:01
...

参考:

http://kdboy.iteye.com/blog/1103794

http://blog.csdn.net/hxpjava1/article/details/7035724

http://blog.itpub.net/23071790/viewspace-709367/

http://www.infoq.com/cn/articles/apache-shiro

org.apache.shiro.spring.web.ShiroFilterFactoryBean DOC

 

在web.xml中配置Shiro的过滤器

 

<filter>
	<filter-name>shiroFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>shiroFilter</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
	<dispatcher>FORWARD</dispatcher>
</filter-mapping>

 可以在<filter></filter>中加入targetFilterLifecycle

 

 

<init-param>
	<param-name>targetFilterLifecycle</param-name>
	<param-value>true</param-value>
</init-param>

如果设置"targetFilterLifecycle"为true,则spring来管理Filter.init()和Filter.destroy();若为false,则这两个方法失效。

 

在Spring的配置文件中添加Shiro的过滤器

 

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
	<property name="securityManager" ref="securityManager" />
	<property name="loginUrl" value="/login" />
	<property name="successUrl" value="/wellcome" />
	<property name="unauthorizedUrl" value="/forbid" />
	<property name="filterChainDefinitions">
		<value>
			/login = authc
			/logout = logout
			/account/** = user
			/admin/** = authcBasic
		</value>
	</property>
</bean>

 这个时候就遇到一个问题,Shiro过滤器都是干什么用的?

anon org.apache.shiro.web.filter.authc.AnonymousFilter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic
org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms
org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port
org.apache.shiro.web.filter.authz.PortFilter
rest
org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles
org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl org.apache.shiro.web.filter.authz.SslFilter
user org.apache.shiro.web.filter.authc.UserFilter

 

写道
rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString
是你访问的url里的?后面的参数。
perms:例子/admins/user/**=perms[user:add:*],perms参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于
isPermitedAll()方法。
roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如/admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要认证才能使用,没有参数
authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查

这些过滤器分为两组,一组是认证过滤器,一组是授权过滤器。其中anon,authcBasic,auchc,user是第一组,
perms,roles,ssl,rest,port是第二组
authcBasic就是弹出一个登录窗口,要求用户输入用户名和密码。适合于对安全性要求不高的系统或设备中,如大家所用路由器的配置页面的认证

还有就是自定义过滤器了,举个官方的例子

 

 <bean id="myCustomFilter" class="com.class.that.implements.javax.servlet.Filter"/>
 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="filterChainDefinitions">
        <value>
            /some/path/** = authc, myCustomFilter
        </value>
    </property>
 </bean>

  

在Spring的配置文件中添加securityManager和realm,加了个ehcache

 

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
	<property name="realm" ref="shiroDbRealm" />
	<property name="cacheManager" ref="shiroEhcacheManager" />
</bean>
<bean id="shiroDbRealm" class="com.**.ShiroDbRealm">
	<property name="accountService" ref="accountService"/>
</bean>
<bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
	<property name="cacheManagerConfigFile" value="classpath:security/ehcache-shiro.xml"/>
</bean>

 

ehcache的配置

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<ehcache updateCheck="false" name="shiroCache">
	<!-- http://ehcache.org/ehcache.xml -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            />
</ehcache>

 

 

又加上了AOP的权限控制和生命周期的配置

 

<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

<!-- AOP式方法级权限检查  -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
	<property name="proxyTargetClass" value="true" />
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
   	<property name="securityManager" ref="securityManager"/>
</bean>

 

以上已经将配置的东西都弄完了,好像很简单的样子

配置完成就是Java的一些实现了,先说Realm

public class ShiroDbRealm extends AuthorizingRealm {

	protected AccountService accountService;

	/**
	 * 认证回调函数,登录时调用.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		User user = accountService.findUserByLoginId(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.getLoginId(), user.getName()), user.getPassword(),
					ByteSource.Util.bytes(salt), getName());
		} else {
			return null;
		}
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
		User user = accountService.findUserByLoginId(shiroUser.loginName);
		if (user != null) {
			Hibernates.initLazyProperty(user.getRoles());
		}
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		for (Role role : user.getRoles()) {
			// 基于Role的权限信息
			info.addRole(role.getName());
			// 基于Permission的权限信息
			info.addStringPermissions(role.getPermissionList());
		}
		return info;
	}

	/**
	 * 设定Password校验的Hash算法与迭代次数.
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(AccountService.HASH_ALGORITHM);
		matcher.setHashIterations(AccountService.HASH_INTERATIONS);

		setCredentialsMatcher(matcher);
	}

	public void setAccountService(AccountService accountService) {
		this.accountService = accountService;
	}
}

 自定义了一个ShiroUser,目的是为了保存更多的用户信息

/**
 * 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息.
 */
public static class ShiroUser implements Serializable {
	private static final long serialVersionUID = -1373760761780840081L;
	public String loginName;
	public String name;

	public ShiroUser(String loginName, String name) {
		this.loginName = loginName;
		this.name = name;
	}

	public String getName() {
		return name;
	}

	/**
	 * 本函数输出将作为默认的<shiro:principal/>输出.
	 */
	@Override
	public String toString() {
		return loginName;
	}

	/**
	 * 重载hashCode,只计算loginName;
	 */
	@Override
	public int hashCode() {
		return Objects.hashCode(loginName);
	}

	/**
	 * 重载equals,只计算loginName;
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		ShiroUser other = (ShiroUser) obj;
		if (loginName == null) {
			if (other.loginName != null) {
				return false;
			}
		} else if (!loginName.equals(other.loginName)) {
			return false;
		}
		return true;
	}
}

 建了两个PO,user,role

public class User implements Serializable {

	private Long id;
	private String loginId;
	private String password;
	private String salt;
	private String name;
	private String email;
	private Integer status;
	private List<Role> roles = Lists.newArrayList();

	... get/set...
}

 

public class Role implements Serializable {

	private Long id;
	private String name;
	private String permissions;

	...get/set...

	public List<String> getPermissionList() {
		return ImmutableList.copyOf(StringUtils.split(permissions, ","));
	}
}

 OK。其他的就是登录页面和Controller了,这个就不说了。

相关标签: spring shiro