今天在用SpringBoot2.X集成Shiro并使用EhCache缓存,集成是比较简单的 #首先编写pom依赖
<!--开启缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--导入shiro依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--添加ehcache-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
#添加配置文件 ehcache.xml,放在资源目录下 可以看到两个xml,上面那个是不小心拼错了,害我找了半天的错,不知道错在哪儿... 另外,修正好后还一直报错,后来删除target文件,重启就好了!在这里也花了挺久的时间。 ehcache.xml文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir"/>
<!-- 默认缓存 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LFU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<!-- 字典元素缓存 -->
<cache name="dictionary"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LFU">
</cache>
</ehcache>
#在启动类上加上@EnableCaching 开启缓存
@SpringBootApplication
@EnableJpaAuditing // 使用jpa自动赋值
@EnableCaching // 开启缓存
public class AdminApplication {
public static void main(String[] args){
SpringApplication.run(AdminApplication.class,args);
}
}
这样就可以使用缓存了。
#然后配置Shiro
编写Shiro的Realm验证,授权逻辑可以根据自己的需求写,参考如下:
public class AuthRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * 授权逻辑 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 获取用户Principal对象 User user = (User) principal.getPrimaryPrincipal(); // 超级管理员获取全部权限 if (user.getId().equals(AdminConst.ADMIN_ID)) { info.addRole(AdminConst.ADMIN_ROLE_NAME); info.addStringPermission("*:*:*"); return info; } // 赋予角色和资源授权 Set<Role> roles = ShiroUtil.getSubjectRoles(); roles.forEach(role -> { info.addRole(role.getName()); role.getMenus().forEach(menu -> { String perms = menu.getPerms(); if (menu.getStatus().equals(StatusEnum.OK.getCode()) && !StringUtils.isEmpty(perms) && !perms.contains("*")) { info.addStringPermission(perms); } }); }); return info; } /** * 认证逻辑 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; // 获取数据库中的用户名密码 User user = userService.getByName(token.getUsername()); // 判断用户名是否存在 if (user == null) { throw new UnknownAccountException(); } else if (user.getStatus().equals(StatusEnum.FREEZED.getCode())) { throw new LockedAccountException(); } // 对盐进行加密处理 ByteSource salt = ByteSource.Util.bytes(user.getSalt()); /* 传入密码自动判断是否正确 * 参数1:传入对象给Principal * 参数2:正确的用户密码 * 参数3:加盐处理 * 参数4:固定写法 */ return new SimpleAuthenticationInfo(user, user.getPassword(), salt, getName()); } /** * 自定义密码验证匹配器 */ @PostConstruct public void initCredentialsMatcher() { setCredentialsMatcher(new SimpleCredentialsMatcher() { @Override public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; SimpleAuthenticationInfo info = (SimpleAuthenticationInfo) authenticationInfo; // 获取明文密码及密码盐 String password = String.valueOf(token.getPassword()); String salt = CodecSupport.toString(info.getCredentialsSalt().getBytes()); return equals(ShiroUtil.encrypt(password, salt), info.getCredentials()); } }); } }
编写ShiroConfig配置类
@Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager, ShiroProjectProperties properties) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); /** * 添加自定义拦截器,重写user认证方式,处理session超时问题 */ HashMap<String, Filter> myFilters = new HashMap<>(16); myFilters.put("userAuth", new UserAuthFilter()); shiroFilterFactoryBean.setFilters(myFilters); /** * 过滤规则(注意优先级) * —anon 无需认证(登录)可访问 * —authc 必须认证才可访问 * —perms[标识] 拥有资源权限才可访问 * —role 拥有角色权限才可访问 * —user 认证和自动登录可访问 */ LinkedHashMap<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/login", "anon"); filterMap.put("/logout", "anon"); filterMap.put("/captcha", "anon"); filterMap.put("/noAuth", "anon"); filterMap.put("/css/**", "anon"); filterMap.put("/js/**", "anon"); filterMap.put("/images/**", "anon"); filterMap.put("/lib/**", "anon"); filterMap.put("/favicon.ico", "anon"); // 通过yml配置文件方式配置的[anon]忽略规则 String[] excludes = properties.getExcludes().split(","); for (String exclude : excludes) { if (!StringUtils.isEmpty(exclude.trim())) { filterMap.put(exclude, "anon"); } } // 拦截根目录下所有路径,需要放行的路径必须在之前添加 filterMap.put("/**", "userAuth"); // 设置过滤规则 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); // 设置登录页面 shiroFilterFactoryBean.setLoginUrl("/login"); // 未授权错误页面 shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth"); return shiroFilterFactoryBean; }
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(AuthRealm authRealm,
EhCacheManager cacheManager,
DefaultWebSessionManager sessionManager,
CookieRememberMeManager rememberMeManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(authRealm);
securityManager.setCacheManager(cacheManager);
securityManager.setSessionManager(sessionManager);
securityManager.setRememberMeManager(rememberMeManager);
return securityManager;
}
/**
* 自定义的Realm
*/
@Bean
public AuthRealm getRealm(EhCacheManager ehCacheManager) {
AuthRealm authRealm = new AuthRealm();
authRealm.setCacheManager(ehCacheManager);
return authRealm;
}
/**
* 缓存管理器-使用Ehcache实现缓存
*/
@Bean
public EhCacheManager ehCacheManager(CacheManager cacheManager) {
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManager(cacheManager);
return ehCacheManager;
}
/**
* session管理器
*/
@Bean
public DefaultWebSessionManager getDefaultWebSessionManager(EhCacheManager cacheManager, ShiroProjectProperties properties) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setCacheManager(cacheManager);
sessionManager.setGlobalSessionTimeout(properties.getGlobalSessionTimeout() * 1000);
sessionManager.setSessionValidationInterval(properties.getSessionValidationInterval() * 1000);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.validateSessions();
// 去掉登录页面地址栏jsessionid
sessionManager.setSessionIdUrlRewritingEnabled(false);
return sessionManager;
}
/**
* rememberMe管理器
*/
@Bean
public CookieRememberMeManager rememberMeManager(SimpleCookie rememberMeCookie) {
RememberMeManager manager = new RememberMeManager();
manager.setCipherKey(Base64.decode("WcfHGU25gNnTxTlmJMeSpw=="));
manager.setCookie(rememberMeCookie);
return manager;
}
/**
* 创建一个简单的Cookie对象
*/
@Bean
public SimpleCookie rememberMeCookie(ShiroProjectProperties properties) {
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
simpleCookie.setHttpOnly(true);
// cookie记住登录信息时间,默认7天
simpleCookie.setMaxAge(properties.getRememberMeTimeout() * 24 * 60 * 60);
return simpleCookie;
}
/**
* 启用shrio授权注解拦截方式,AOP式方法级权限检查
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
``` ※这里说明一下,上图中红色提示可以忽略。这里是配置Shiro的缓存管理器org.apache.shiro.cache.ehcach.EhCacheManager,上面方法的参数是把Spring容器中的cacheManager对象注入到EhCacheManager中,这样就实现了Shiro和缓存注解使用同一种缓存方式。
本文由博客群发一文多发等运营工具平台 OpenWrite 发布