shiro使用教程
一、shiro是什么
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。不仅可以在Web项目中使用,在普通的项目中也是可以使用的
二、shiro可以做什么
shiro可以进行细粒度地权限控制,包括对方法,对链接,对页面显示进行权限控制。
三、在Web项目中使用shiro进行权限管理
1、 在web.xml中添加shiro的拦截器
<filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
2、 spring-mvc.xml中添加shiro的权限注解支持
<aop:config proxy-target-class="true"></aop:config> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>
3、 使用spring对ehcache进行缓存管理
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:cache="http://www.springframework.org/schema/cache" 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 http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!-- 支持缓存注解 --> <cache:annotation-driven cache-manager="ehcacheManager" /> <!--ehcache--> <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache.xml"/> </bean> <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="cacheManagerFactory"/> </bean> </beans>
4、 使用ehcache进行缓存管理
在ehcache中添加如下缓存块
<diskStore path="java.io.tmpdir"/> <cache name="authorizationCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> <cache name="authenticationCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> <cache name="shiro-activeSessionCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache>
5、实现CacheManager的接口,对shiro权限使用spring进行缓存管理
public class SpringCacheManagerWrapper implements CacheManager { private org.springframework.cache.CacheManager cacheManager; /** * 设置spring cache manager * * @param cacheManager */ public void setCacheManager(org.springframework.cache.CacheManager cacheManager) { this.cacheManager = cacheManager; } @Override public <K, V> Cache<K, V> getCache(String name) throws CacheException { org.springframework.cache.Cache springCache = cacheManager.getCache(name); return new SpringCacheWrapper(springCache); } static class SpringCacheWrapper implements Cache { private org.springframework.cache.Cache springCache; SpringCacheWrapper(org.springframework.cache.Cache springCache) { this.springCache = springCache; } @Override public Object get(Object key) throws CacheException { Object value = springCache.get(key); if (value instanceof SimpleValueWrapper) { return ((SimpleValueWrapper) value).get(); } return value; } @Override public Object put(Object key, Object value) throws CacheException { springCache.put(key, value); return value; } @Override public Object remove(Object key) throws CacheException { springCache.evict(key); return null; } @Override public void clear() throws CacheException { springCache.clear(); } @Override public int size() { if(springCache.getNativeCache() instanceof Ehcache) { Ehcache ehcache = (Ehcache) springCache.getNativeCache(); return ehcache.getSize(); } throw new UnsupportedOperationException("invoke spring cache abstract size method not supported"); } @Override public Set keys() { if(springCache.getNativeCache() instanceof Ehcache) { Ehcache ehcache = (Ehcache) springCache.getNativeCache(); return new HashSet(ehcache.getKeys()); } throw new UnsupportedOperationException("invoke spring cache abstract keys method not supported"); } @Override public Collection values() { if(springCache.getNativeCache() instanceof Ehcache) { Ehcache ehcache = (Ehcache) springCache.getNativeCache(); List keys = ehcache.getKeys(); if (!CollectionUtils.isEmpty(keys)) { List values = new ArrayList(keys.size()); for (Object key : keys) { Object value = get(key); if (value != null) { values.add(value); } } return Collections.unmodifiableList(values); } else { return Collections.emptyList(); } } throw new UnsupportedOperationException("invoke spring cache abstract values method not supported"); } } }
6、自定义放在session中的实体
public class CustomPrincipal implements Serializable { private Integer id; private String username; public CustomPrincipal(String username) { this.username = username; } public CustomPrincipal(int id, String username) { this.id = id; this.username = username; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } /** * 本函数输出将作为默认的<shiro:principal/>输出. */ @Override public String toString() { return username; } }
7、重写realm
public class AdministratorRealm extends AuthorizingRealm { private AdministratorService administratorService; public AdministratorService getAdministratorService() { return administratorService; } public void setAdministratorService(AdministratorService administratorService) { this.administratorService = administratorService; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { CustomPrincipal customPrincipal = (CustomPrincipal)principals.getPrimaryPrincipal(); String username = customPrincipal.getUsername(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); Set<String> roles = administratorService.getRoles(username); roles.add(UserConstants.ADMINISTRATOR_STR); authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(administratorService.getPermissions(username)); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String username = (String)usernamePasswordToken.getPrincipal(); Administrator administrator = administratorService.getAdministrator(username); if (administrator == null) { throw new UnknownAccountException();//没找到帐号 } if (Boolean.FALSE.equals(administrator.getAdmiStatus())) { throw new LockedAccountException(); //帐号锁定 } CustomPrincipal principal = new CustomPrincipal(administrator.getAdmiId(), administrator.getAdmiAccount()); //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( principal, //用户名 administrator.getAdmiPassword(), //密码 ByteSource.Util.bytes(administrator.getCredentialsSalt()),//salt=username+salt getName() //realm name ); return authenticationInfo; } @Override public void clearCachedAuthorizationInfo(PrincipalCollection principals) { super.clearCachedAuthorizationInfo(principals); } @Override public void clearCachedAuthenticationInfo(PrincipalCollection principals) { super.clearCachedAuthenticationInfo(principals); } @Override public void clearCache(PrincipalCollection principals) { super.clearCache(principals); } public void clearAllCachedAuthorizationInfo() { getAuthorizationCache().clear(); } public void clearAllCachedAuthenticationInfo() { getAuthenticationCache().clear(); } public void clearAllCache() { clearAllCachedAuthenticationInfo(); clearAllCachedAuthorizationInfo(); } }
8、spring-shiro.xml实例化类
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <aop:config proxy-target-class="true"></aop:config> <!-- 缓存管理器 --> <bean id="cacheManager" class="com.misuosi.mshop.shiro.cache.SpringCacheManagerWrapper"> <property name="cacheManager" ref="ehcacheManager"/> </bean> <!-- 凭证匹配器 --> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="md5"/> <property name="hashIterations" value="2"/> <property name="storedCredentialsHexEncoded" value="true"/> </bean> <!-- Realm实现 --> <bean id="administratorRealm" class="com.misuosi.mshop.shiro.realm.AdministratorRealm"> <property name="administratorService" ref="administratorService"/> <property name="credentialsMatcher" ref="credentialsMatcher"/> <property name="cachingEnabled" value="false"/> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> </bean> <!-- 会话ID生成器 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- 会话Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="-1"/> </bean> <!-- 会话DAO --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/> <property name="sessionIdGenerator" ref="sessionIdGenerator"/> </bean> <!-- 会话验证调度器 --> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> <property name="sessionValidationInterval" value="1800000"/> <property name="sessionManager" ref="sessionManager"/> </bean> <!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/> <property name="sessionDAO" ref="sessionDAO"/> <property name="sessionIdCookieEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="administratorRealm"/> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> </bean> <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <!-- 基于Form表单的身份验证过滤器 --> <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <property name="successUrl" value="/admin/index"/> <property name="loginUrl" value="/admin/login"/> </bean> <bean id="adminLogoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="/admin/login"/> </bean> <!-- Shiro的Web过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="filters"> <util:map> <entry key="adminAuthc" value-ref="formAuthenticationFilter"/> <entry key="adminLogout" value-ref="adminLogoutFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /admin/login = adminAuthc /admin/logout = adminLogout /admin/** = adminAuthc,roles[admin] </value> </property> </bean> <!-- Shiro生命周期处理器--> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
9、freemarker使用shiro的标签
把标签的实现贴到freemarker.tag的包中,在freemarker的配置中添加freemarker标签。
public class ShiroTagFreeMarkerConfigurer extends FreeMarkerConfigurer { @Override public void afterPropertiesSet() throws IOException, TemplateException { super.afterPropertiesSet(); this.getConfiguration().setSharedVariable("shiro", new ShiroTags()); } }
10、完成