天天看点

Web安全-Shiro-记住我功能

在《Web安全-使用Shiro做认证和访问控制》 中,我简单了说明了shiro的用法,今天来讲下利用shiro怎么实现记住我功能,如下图:

Web安全-Shiro-记住我功能

如果勾选了记住我,那么在关闭浏览器或服务器重启后,用户打开网站会自动登录进去,无需再次输入密码。

据我了解,记住我功能应该是shiro把用户信息序列化到cookie中,传到后台的时候再解密的。

需要增加记住我相关的配置:

/**
 * rememberMe管理器, cipherKey生成见{@code Base64Test.java}
 */
@Bean
public CookieRememberMeManager rememberMeManager(SimpleCookie rememberMeCookie) {
   CookieRememberMeManager manager = new CookieRememberMeManager();
   manager.setCipherKey(Base64.decode("Z3VucwAAAAAAAAAAAAAAAA=="));
   manager.setCookie(rememberMeCookie);
   return manager;
}

/**
 * 记住密码Cookie
 */
@Bean
public SimpleCookie rememberMeCookie() {
   SimpleCookie simpleCookie = new SimpleCookie(REMEMBERME_KEY);
   simpleCookie.setHttpOnly(true);
   simpleCookie.setMaxAge(REMEMBERME_TIMEOUT);
   return simpleCookie;
}

/**
 * session管理器(单机环境)
 */
@Bean
public DefaultWebSessionManager defaultWebSessionManager(CacheManager cacheShiroManager) {
   DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
   sessionManager.setCacheManager(cacheShiroManager);
   sessionManager.setDeleteInvalidSessions(true);
   sessionManager.setSessionValidationSchedulerEnabled(true);
   Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
   cookie.setName("shiroCookie");
   cookie.setHttpOnly(true);
   sessionManager.setSessionIdCookie(cookie);
   return sessionManager;
}
           

利用SecurityUtils工具类可以获取信息:

// 获取信息
return (UserPageModel) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal();
// 是在shiro登录鉴权的时候放入的,就是从库里查询的user对象
UserModel user = loginService.getLoginUserByMobile(token.getUsername());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
           

但是一般我们都是从session中获取指定的key作为是否登录的依据,但是session超时、关闭浏览器或重启服务器后就不行了,所以我们要修改相应的代码。

我们是统一了获取session的方法,所以直接在这个方法中处理就好了。其他情况可以使用拦截器解决。

public AdminSessionInfo getSessionInfo() {
	Object sessionInfoObj = request.getSession().getAttribute(Constant.ADMIN_SESSION_INFO);
	if (sessionInfoObj != null) {
		log.debug("sessionInfo已存在sesssion中, 无需从数据库查询!");
		return (AdminSessionInfo) sessionInfoObj;
	}

	UserPageModel shiroUser = ShiroUtil.getSessionUser();
	if (shiroUser == null) {
		return null;
	}
   // 我们session中包装了用户部门、角色等信息,所以还需要查库一次(会先走缓存)
	AdminSessionInfo sessionInfo = loginService.getSessionInfoByUserId(ShiroUtil.getSessionUser());
	if (sessionInfo != null) {
		log.debug("首次获取sessionInfo, 需要从数据库中查询!");
		ShiroUtil.setSessionAttr(Constant.ADMIN_SESSION_INFO, sessionInfo);
		return sessionInfo;
	}

	return null;
}
           

记录下配置过程,以及踩的坑。

  • 在shiro中,session和rememberMe的cookie是分开的,名字都是可以自定义的
  • 浏览器清除缓存后,记住我功能会失效
  • 注意user实体需要序列化
  • 记住我subject.isRemembered为true、subject.isAuthenticated为false,登录的则相反
  • rememberme登录的用户,只能访问user权限控制的路径,authc还需要登录的。比如强制下单的时候必须登录

有一些敏感性的操作,比如删除数据、下单等,可以将权限设置为authc级别,如果是记住我自动登录的,需要再次引导用户输入密码确认。

可通过覆盖shiro默认的authc级别拦截器来实现。

继续阅读