Shiro使用RememberMe添加数据到Session

首先来理清一下session和rememberMe的功能,session是大家比较熟悉的功能,因为HTTP协议是无状态的,网站为了在多个请求之间传递数据就使用了session这个东西,session是存储在网站服务器上的某个地方,比如内存、数据库或者其他的什么东西,在我的配置中是用Ehcache存储的,因为我使用了Shiro的Native Session Manager,替代了Tomcat本身的Session Manager,并且为Shiro的Native Session Manager配置了Ehcache的SessionDAO:

    @Bean
    public SessionDAO sessionDAO() {
        return new EnterpriseCacheSessionDAO();
    }

    //使用Shiro自带的Session管理器
    @Bean
    public WebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(sessionDAO());
//        sessionManager.setGlobalSessionTimeout(300000);
        //设置Cookie中返回的SessionID的名字,默认是JSESSIONID
          sessionManager.getSessionIdCookie().setName("XXXXXXSESSIONID");
        return sessionManager;
    }

在这种情况下服务器的Session就存储在Ehcache里面,如果某个Session过期(比如关闭了浏览器或者超时),此条Session就会从Ehcache里面永久删除,下次的请求将不能使用Session里面的数据。所以说即使有些url设置的是”user”级别的(也就是说不用登录即可访问,只须设置了rememberMe),但是如果这些url使用了Session里面的数据,就会抛出异常,因为此时这个用户对应的Session已经不存在了。

再来看一下RememberMe的功能是怎样的。RememberMe是用于这样的一种场景:当浏览一个网站的时候,网站返回给你一个Session Cookie和一个RememberMe Cookie,Session Cookie很好理解,就是为了此次的对话,一旦关闭了浏览器或者超时了Session Cookie就没用了。但是RememberMe Cookie不太一样,Shiro默认的RememberMe Cookie的时长是一年,所以不用担心这个Cookie的情况。RememberMe Cookie实际就是Shiro把这个用户的信息加密一下放到cookie里面,下次就可以根据这个cookie来进行判断这是哪个用户。Shiro使用RememberMe功能的方式很简单,这里就不介绍了。

下面讲一下怎么根据这个RememberMe Cookie来向Session里面添加一些数据以便可以在不登录的情况下进行一些操作,方法就是自定义一个Filter:

package com.iot.baobiao.shiro;

import com.iot.baobiao.dao.UserDaoInterface;
import com.iot.baobiao.jooq.tables.pojos.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.servlet.OncePerRequestFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/**
 * Created by jia on 16-12-5.
 */

//为了使用RemenberMe Cookie,RememberMe Cookie里面是加密的Principle,
// 所以需要从这个Principle找出对应的user_id和phonenum放到Session里面
public class AddPrincipalToSessionFilter extends OncePerRequestFilter {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    UserDaoInterface userDaoInterface;

    @Override
    protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isRemembered()) {
            String phonenum = subject.getPrincipal().toString();
            User user = userDaoInterface.fetchOneByPhonenum(phonenum);
            if (user == null) return;
            Session session = subject.getSession(false);
            session.setAttribute("phonenum", phonenum);
            session.setAttribute("user_id", user.getId());
            logger.debug("Add principal info to session: " + phonenum);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

Shiro会自动解密RememberMe Cookie里面的Principal,我们只需调用当前Subject的函数就行了。然后在Spring配置文件中添加上这个自定义的Shiro Filter就可以了:

    //Shiro自定义过滤器
    @Bean
    public AddPrincipalToSessionFilter addPrincipalToSessionFilter() {
        return new AddPrincipalToSessionFilter();
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();

        Map<String, Filter> map = new HashMap<>();
        map.put("addPrincipal", addPrincipalToSessionFilter());
        shiroFilter.setFilters(map);
//        shiroFilter.

        Map<String, String> definitionsMap = new HashMap<String, String>();
        definitionsMap.put("/unauthenticated", "anon");
        definitionsMap.put("/login", "anon");
        definitionsMap.put("/verification", "anon");
        definitionsMap.put("/forgetPassword", "anon");
        definitionsMap.put("/signup", "anon");
        definitionsMap.put("/index.jsp", "anon");
        definitionsMap.put("/", "anon");
        definitionsMap.put("/pay/**", "authc");
        definitionsMap.put("/admin/**", "authc, roles[admin]");
        //在每个可以使用RememberMe功能进行访问的url上面都添加这个自定义的Filter
        definitionsMap.put("/**", "addPrincipal, user");
        shiroFilter.setFilterChainDefinitionMap(definitionsMap);

        shiroFilter.setLoginUrl("/unauthenticated");
        shiroFilter.setUnauthorizedUrl("/unauthorized");
        shiroFilter.setSecurityManager(securityManager());

        logger.info("Shiro Filters: " + shiroFilter.getFilters());
        return shiroFilter;
    }

在Session超时之后再进行访问,即使对应的url使用了session里面的数据也可以正常使用了,比如说使用了Session的getAttribute函数也是可以的,如果没有这个自定义的Filter则会出现空指针错误。查看一下输出的日志,发现有这么一行:

2016-12-06 12:39:31 DEBUG AddPrincipalToSessionFilter:42 - Add principal info to session: 189xxxxxx06

这在手机App上面尤其有用,因为如果每次用户使用手机App都需要登录的话用户体验就会非常差,添加了自定义的Filter之后就可以很长时间不用登录,同时也不用把Session的过期时间设为很长,以免大量占用服务器资源。

Shiro的RememberMe功能可以帮助用户在关闭浏览器后也能保持登录状态,实现方法是在用户登录时,生成一个RememberMe Cookie,并将它保存在用户的浏览器中。下次用户再次访问网站时,如果没有进行登录操作,Shiro会自动读取这个Cookie,从而实现自动登录。 为了保持用户的状态,在生成RememberMe Cookie时,可以设置它的过期时间。如果没有设置过期时间,Cookie将在浏览器关闭时自动删除。 下面是一个示例代码,演示如何生成RememberMe Cookie并设置它的过期时间: ``` // 创建一个RememberMe Cookie SimpleCookie rememberMeCookie = new SimpleCookie("rememberMe"); // 设置Cookie的过期时间为7天 rememberMeCookie.setMaxAge(7 * 24 * 60 * 60); // 将Cookie保存到用户的浏览器中 Subject currentUser = SecurityUtils.getSubject(); currentUser.getSession().setAttribute("rememberMeCookie", rememberMeCookie); ``` 在上述代码中,我们创建了一个名为rememberMe的Cookie,并将它的过期时间设置为7天。接着,我们将Cookie保存到用户的Session中,以便在下次访问网站时可以读取它。 为了读取RememberMe Cookie,我们可以在Shiro的配置文件中添加如下内容: ``` [main] securityManager.rememberMeManager.cookie = org.apache.shiro.web.servlet.SimpleCookie securityManager.rememberMeManager.cookie.name = rememberMe securityManager.rememberMeManager.cookie.maxAge = 604800 securityManager.rememberMeManager.cipherKey = kPH+bIxk5D2deZiIxcaaaA== ``` 在这个配置中,我们设置了RememberMe Cookie的名称为rememberMe,并将它的过期时间设置为7天。如果想要读取更多的Cookie属性,可以查看SimpleCookie类的API文档。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值