今天在用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,放在资源目录下
![](https://img.haomeiwen.com/i19619362/e356c3ecd3664516.png)
可以看到两个xml,上面那个是不小心拼错了,害我找了半天的错,不知道错在哪儿...
![](https://img.haomeiwen.com/i19619362/b19d720ac3eaaae6.png)
另外,修正好后还一直报错,后来删除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;
}
}
![](https://img.haomeiwen.com/i19619362/8a49708edcd787b7.png)
※这里说明一下,上图中红色提示可以忽略。这里是配置Shiro的缓存管理器org.apache.shiro.cache.ehcach.EhCacheManager,上面方法的参数是把Spring容器中的cacheManager对象注入到EhCacheManager中,这样就实现了Shiro和缓存注解使用同一种缓存方式。
网友评论