shiro自动登录及session失效解决办法(1详解)不用缓存

这是一个困扰了我一周的问题,几乎找遍了全网,也没有找到合适的解决办法,问题的难度在于,不使用任何缓存技术,实现以下问题。

1、当用户登录时,使用shiro rememberme,加密保存cookie 到本地。

2、当用户再次登录时是自动登录状态,但是这时候是没有session的,这里就要解决session的问题。

这里用到的是idea项目:springboot+shiro

文件目录:

让我们从自动登录开始:

一、配置shiroconfig

//cookie
@Bean
public SimpleCookie rememberMeCookie(){
    SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
    //只能通过http访问cookie,js不能
    simpleCookie.setHttpOnly(true);
    simpleCookie.setPath("/");
    //<!-- 记住我cookie生效时间30天 ,单位秒;-->
    simpleCookie.setMaxAge(2678400);
    return simpleCookie;
}
/**
 * cookie管理对象;
 * rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中
 * @return
 */
@Bean("emanager")
public CookieRememberMeManager rememberMeManager(){
    CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
    cookieRememberMeManager.setCookie(rememberMeCookie());
    //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
    cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
    return cookieRememberMeManager;
}

//桥梁---这里只添加下面配置记住我这句
@Bean("manager")
public SecurityManager securityManager(@Qualifier("realm") MyRealm realm, @Qualifier("emanager")RememberMeManager emanager){
    DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
    ....
    //配置记住我
    manager.setRememberMeManager(emanager);
    return  manager;
}
//进行全局验证配置
@Bean("shiroFilter")
public ShiroFilterFactoryBean shirofilter(@Qualifier("manager") SecurityManager manager){
    ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
    //配置记住我
    bean.setSecurityManager(manager);
    ....
    return bean;
}

二、controller,这里的时候要注意,一般来讲,“自动登录、记住密码、七天免登录”这是用户选择的,这里由于业务需要,直接写死,每个用户都要自动登录,所以在下面的行代码中,最后一个直接给了true,如果你需要用户选择,请在前台设置复选框,在参数中接收用户的选择,像第二行代码这样,第三个参数用来接收用户选择。

//第一种:写死
UsernamePasswordToken token=new UsernamePasswordToken(phone, password,true);
//第二种:前台传值
<input type="checkbox" name="isRememberMe" value="1" /> 记住我
public ModelAndView tologin(String phone, String password,@RequestParam(value="isRememberMe", defaultValue="0") Integer isRememberMe){
    UsernamePasswordToken token=new UsernamePasswordToken(phone, password);
    if (isRememberMe == 1) {
            token.setRememberMe(true);
        }
}

到此,记住我功能(自动登录功能)已经完成了,接下来是解决session失效的问题,思路:当用户是自动状态登录的时候,我们写一个拦截器,拦截它,获取cookie中的数据,然后到数据库中查询,再重新设置session。

下面给出代码,新建一个类

package com.lynu.esmarket.config;

import com.lynu.esmarket.bean.Login;
import com.lynu.esmarket.service.LoginService;
import org.apache.shiro.SecurityUtils;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.servlet.OncePerRequestFilter;

import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import java.io.IOException;

/**
 * Created by jia on 19-4-15.
 */
public class AddPrincipalToSessionFilter extends OncePerRequestFilter {
    @Autowired
    LoginService ls;

    @Override
    protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
        //查询当前用户的信息
        Subject subject = SecurityUtils.getSubject();
        //判断用户是不是通过自动登录进来的
        if (subject.isRemembered()) {
            //如果是,则获取它的手机号(我的登录是以手机号+密码登录的)
            String phone = subject.getPrincipal().toString();
            if(phone==null){
                return;
            }
            //根据手机号查询该用户的信息
            Login login = ls.queryuser(phone);
            if (login == null) return;
            //由于是继承的OncePerRequestFilter,没办法设置session
            //这里发现可以将servletReques强转为子类,所以使用request.getsiion())
            HttpServletRequest request=(HttpServletRequest) servletRequest;
            HttpSession session=request.getSession();
            //当session为空的时候
            if (session.getAttribute("login")==null){
                //把查询到的用户信息设置为session,时效为3600秒
                session.setAttribute("login",login);
                session.setMaxInactiveInterval(3600);
            }
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

 设置shiroconfig

//在shiroconfig中设置
//Shiro自定义过滤器,注意写在@Bean("shiroFilter")的上边
@Bean
public OncePerRequestFilter addPrincipalToSessionFilter() {
    return new AddPrincipalToSessionFilter();
}
//在@Bean("shiroFilter")中配置如下
@Bean("shiroFilter")
public ShiroFilterFactoryBean shirofilter(@Qualifier("manager") SecurityManager manager){
    //shiro对象
    ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
    //配置记住我
    bean.setSecurityManager(manager);
    //配置刚刚写的拦截器
    Map<String, Filter> fmap = new HashMap<>();
    fmap.put("addPrincipal", addPrincipalToSessionFilter());
    bean.setFilters(fmap);
    //所有是user能够访问的都要进行过滤,注意:这个user是shiro中内置的,在remember状态下
    //所有自动登录的用户都是user状态
    map.put("/**","addPrincipal,user");//需要进行权限验证
    其他的就省略了....
    bean.setFilterChainDefinitionMap(map);
    
    return bean;
}

猜你喜欢

转载自blog.csdn.net/weixin_42886104/article/details/89310243