当前位置 博文首页 > 快乐的小三菊的博客:springboot + shiro 实现自己的登出
? ? ? ?如果想要实现登出功能,常见的实现方式就是在?ShiroConfig 类的?shiroFilterFactoryBean() 方法中配置一个标签,这种方式是 shiro 自带的登出方式,只要拦截到访问 /logout 的请求,就会被 logout 对应的 LogoutFilter 拦截,自动登出。配置如下所示:
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
// ....
Map<String, String> map = new LinkedHashMap<>();
// logout 使用的是 shiro 提供的过滤器
map.put("/logout", "logout");
shiroFilter.setFilterChainDefinitionMap(map);
// ....
return shiroFilter;
}
? ? ? ?为什么要实现自己的自定义登出?虽然 shiro 的默认登出会清理用户的 session 信息,并且也会清理掉 redis 中缓存的?用户身份认证?和?授权认证?的相关信息。但是有时候,我们还有自己的一些业务需要处理,比如说前面做的 ”限制用户的登录次数“ 和 ”并发登录的人数“,使用 shiro 的默认登出时这些是不会被删除的,假如我们想要删除这些 key 呢? 或者说在用户登出时,要记录一些日志信息存储当前用户在线时长等等,这个时候我们就需要是实现自定义登出。
? ? ? ?方式一:不配置默认的 logout ,在自己的 controller 中写一个方法对外提供 http 接口,实现自己的登出逻辑,参考代码如下所示:
@RequestMapping("/logout")
@ResponseBody
public String logout(String userName) {
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
? ? ? ?方式二:写一个类继承?LogoutFilter 过滤器,并重写 preHandle() 方法。代码如下所示:
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import com.shiro.CustomRealm;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @description: 自定义 LogoutFilter
*/
public class ShiroLogoutFilter extends LogoutFilter {
/**
* 自定义登出,登出之后,清理当前用户redis部分缓存信息
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
// 登出操作 清除缓存 subject.logout() 可以自动清理缓存信息, 这些代码是可以省略的 这里只是做个笔记 表示这种方式也可以清除
Subject subject = getSubject(request,response);
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
CustomRealm shiroRealm = (CustomRealm) securityManager.getRealms().iterator().next();
PrincipalCollection principals = subject.getPrincipals();
shiroRealm.clearCache(principals);
// 登出
subject.logout();
// 获取登出后重定向到的地址
String redirectUrl = getRedirectUrl(request,response,subject);
// 重定向
issueRedirect(request,response,redirectUrl);
return false;
}
}
? ? ? ?然后在 ShiroConfig 类中配置 shiroLogoutFilter ,需要注意的是在配置?shiroLogoutFilter 时,这个类不需要加 @Bean 注解。
public ShiroLogoutFilter shiroLogoutFilter(){
ShiroLogoutFilter shiroLogoutFilter = new ShiroLogoutFilter();
//配置登出后重定向的地址,等出后配置跳转到登录接口
shiroLogoutFilter.setRedirectUrl("/login");
return shiroLogoutFilter;
}
? ? ? ?最后一步,将配置的 shiroLogout 注入到?ShiroFilterFactoryBean 中,代码如下所示:
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
// ....
LinkedHashMap<String, Filter> filtersMap = new LinkedHashMap<>();
// logout 将执行自定义的filter 不再走默认的LogoutFilter
filtersMap.put("logout", shiroLogoutFilter());
shiroFilter.setFilters(filtersMap);
// ....
shiroFilter.setFilterChainDefinitionMap(map);
return shiroFilter;
}
? ? ? ?无论是使用 subject.logout() 还是使用 shiroRealm?中的自定义方法 shiroRealm.clearCache(principals) ,都只能清除权限的缓存信息,?却无法清除 redis 中身份认证的缓存信息,?如下,具体如何解决这个问题,请看我的下一篇文章。
?
cs