Shiro最佳实践(七)Spring集成与EhCache
Apache Shiroadmin 发布于:2019-08-04 18:01:16
阅读:loading
就笔者现在而言,深入与Spring集成才是最终的方向,同时将常用的一系列授权相关功能给做到期望的程度,所以在于spring集成时考虑了实现以下功能点:
1、登录/退出;
登录支持自定义登录/退出,验证码支持(本例中验证码只是模拟,并未使用图片),记住我,登录失败错误提示等。
2、权限控制;
权限功能模拟从数据库中获取,权限控制及未授权页面显示;
3、用户授权缓存;
集成EhCache实现用户授权信息缓存;
package cn.chendd.shiro.examples.commponent;
import ...
/**
* @author chendd
* @date 2019/6/15 1:22
* 自定义认证实现
*/
public class EncryptionRealmEhCache extends AuthorizingRealm implements Serializable {
private static final long serialVersionUID = 818010090715013851L;
@Resource
private ISysUserService sysUserService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo author = new SimpleAuthorizationInfo();
Set<String> roles = new HashSet<>();
roles.add("userManager");
author.setRoles(roles);
Set<String> perms = new HashSet<>();
perms.add("user:queryList");
author.addStringPermissions(perms);
return author;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
String userName = userToken.getUsername();
SysUser sysUser = sysUserService.getSysUserByUserName(userName);
if(sysUser == null){
throw new UnknownAccountException();
}
String passWord = sysUser.getPassWord();
if(! "ENABLE".equals(sysUser.getStatus())){
throw new LockedAccountException();
}
String encodePassword = encodePassword(new String(userToken.getPassword()) , userName);
if(!encodePassword.equals(passWord)){
throw new IncorrectCredentialsException();
} else if(false){
//密码错误次数过多
throw new ExcessiveAttemptsException();
}
SimpleAuthenticationInfo auth = new SimpleAuthenticationInfo(sysUser.getUserName() , token.getCredentials() , this.getName());
return auth;
}
public static String encodePassword(Object source, String salt) {
Md5Hash md5 = new Md5Hash(source, salt, 7);
return md5.toHex();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<aop:config proxy-target-class="true"></aop:config>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<bean id="customLoginFormFilter" class="cn.chendd.shiro.examples.commponent.CustomLoginFormFilter">
<property name="usernameParam" value="userName"/>
<property name="passwordParam" value="passWord"/>
<property name="rememberMeParam" value="remMe"/>
<!-- 可设置登录成功后的响应地址 -->
<!--<property name="successUrl" value="/index" />-->
</bean>
<bean id="customLogoutFilter" class="cn.chendd.shiro.examples.commponent.CustomLogoutFilter"></bean>
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!--删除由直接关闭浏览器造成的无退出问题-->
<property name="deleteInvalidSessions" value="true" />
<!-- 定时执行session销毁 -->
<property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
<!--<property name="sessionValidationInterval" value="10000" />--><!-- 该参数未发现明显作用 -->
<!-- 需要让此session可以使用该定时调度器进行检测 -->
<property name="sessionValidationSchedulerEnabled" value="true"/>
<!-- 定义的是全局的session会话超时时间,此cao作会覆盖web.xml文件中的超时时间配置 -->
<property name="globalSessionTimeout" value="#{30 * 60 * 1000}" />
<!-- 所有的session一定要将id设置到Cookie之中,需要提供有Cookie的cao作模版-->
<property name="sessionIdCookie">
<bean class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="shiro.session.id.cookie" />
</bean>
</property>
<!-- 定义sessionIdCookie模版可以进行cao作的启用 -->
<property name="sessionIdCookieEnabled" value="true"/>
<!-- 引用session缓存的相关配置 -->
<!--<property name="cacheManager" ref="shiroRedisCacheManager" />-->
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="encryptionRealm" />
<!--session过期策略-->
<property name="sessionManager" ref="sessionManager" />
<!--记住我-->
<property name="rememberMeManager" ref="rememberMeManager" />
<!-- 启用session的缓存 -->
<property name="cacheManager" ref="shiroEhCacheManager" />
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/index" />
<property name="unauthorizedUrl" value="/unauth" />
<property name="filterChainDefinitions">
<value>
/favicon.ico = anon
/logout = logout
/login = authc
/** = authc
</value>
</property>
<property name="filters">
<map>
<entry key="authc" value-ref="customLoginFormFilter"></entry>
<!--<entry key="logout" value-ref="customLogoutFilter"></entry>-->
</map>
</property>
</bean>
<bean id="rememberCookies" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe"></constructor-arg>
<property name="httpOnly" value="true"></property>
<property name="maxAge" value="#{60*60*24}"></property>
</bean>
<!-- 配置记住我管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<!-- 加密的base64,末尾拼接以A=结束,此处给的是88888888 -->
<!--<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('ODg4ODg4ODgAA==')}"/>-->
<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('6ZmI6I2j5Y+R5aSn5ZOlAA==')}"/>
<property name="cookie" ref="rememberCookies"/>
</bean>
<!-- 解决shiro配置的没有权限访问时,unauthorizedUrl不跳转到指定路径的问题 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.apache.shiro.authz.UnauthorizedException">/unauth</prop>
</props>
</property>
</bean>
<!-- session存储配置 -->
<!-- 定义Session ID生成管理器,默认session.getId生成的规则就是uuid -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />
<!-- 配置session的定时验证检测程序类,以让无效的session释放 -->
<bean id="sessionValidationScheduler"
class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
<!-- 设置session的失效扫描间隔,会清空掉过期失效session数据,单位为毫秒,默认3600000 -->
<property name="sessionValidationInterval" value="1800000"/>
<!-- 随后还需要定义有一个会话管理器的程序类的引用 -->
<property name="sessionManager" ref="sessionManager"/>
</bean>
<bean id="encryptionRealm" class="cn.chendd.shiro.examples.commponent.EncryptionRealmEhCache">
<property name="name" value="encryptionRealm" />
<!--<property name="credentialsMatcher" ref="credentialsMatcher" />-->
<!-- 启用用户权限的缓存,使用ehcache.xml中定义的名称 -->
<!--<property name="authorizationCacheName" value="shiro-AuthorizationInfo" />-->
<!--<property name="cacheManager" ref="shiroRedisCacheManager" />-->
</bean>
<!--<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5" />
<property name="hashIterations" value="7" />
</bean>-->
<!-- spring继承ehcache的缓存配置 -->
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
<!-- shiro封装cacheManager -->
<bean id="shiroEhCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="ehCacheManager" />
</bean>
<!-- spring 封装ehcache缓存管理器 -->
<bean id="springCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehCacheManager" />
</bean>
<!-- 激活spring 缓存注解 -->
<cache:annotation-driven cache-manager="springCacheManager" />
</beans>
说明:登录账号信息有:chendd/chendd123和sunm/sunm123;
这里给出核心自定义Realm与spring-shiro.xml配置文件,完整示例请转至开篇或尾篇处下载。
点赞