问题描述
目前系统包括一个Web网站系统和一个微信公众号,Web网站系统和微信公众号共用相同的用户信息。需要实现的功能是Web网站系统用户登录系统后,当在其他地方同时登录该用户信息,能够将前面那个用户挤下来并让后面那个用户信息登录(和微信多个地方登录类似);而微信公众号则若用户登录微信公众号,需要先绑定用户信息,绑定成功后,微信公众号用户将不需要再次登录,除非退出或者openID失效,而其他用户再次用这个账号绑定微信公众号时将不再绑定成功。同时微信公众号和Web网站系统能够同时同一个用户在线,当管理员将用户删除后,Web用户能够及时下线及微信公众号退出。
问题处理
- Web网站系统:用户一开始登录,将用户ID和sessionID写入到Redis数据库中(键值对保存)及将用户信息、登录类型写入session
- 微信公众号:微信公众号绑定及登录,将公众号的OpenID和sessionID写入到Redis数据库(键值对保存)及将用户信息、登录类型写入session
编写一个过滤器,对所有需要登录权限的请求拦截,获取用户的登录类型及用户信息
- 用户未登录,则直接提示用户未登录,返回到登录界面
- 用户已登录且为微信登录,则根据用户的openID获取保存在Redis中的sessionID
- 用户已登录且为Web网站系统用户,则根据用户的ID获取保存在Redis中sessionID
- 若redis中保存的sessionID为空,则提示用户未登录系统
- 若Redis中保存的sessionID不为空且和当前用户的sessionID不一样,则当前用户被挤下来了,需要清除session并返回到登录界面
- 若Redis中保存的sessionID不为空且和当前用户的sessionID一样,则继续
- 当删除用户后,需要将Redis清空
系统需要监听sesison创建和销毁,当session销毁时,需要清理session中redis中缓存的数据
- 系统设置为30分钟session过期,微信公众号需要自己根据OpenID自动登录微信公众号
问题解决
- 用户登录:
if(user==null){
throw new PhyException(PhyException.NoEntity,"请填写用户信息");
}
User user2 =userService.loading(user.getLoginName(), user.getTextPwd());
if (user2 != null) {
session.setAttribute("user", user2);
session.setAttribute("loginType", "web");
userSessionRedisService.add(user2.getId(), session.getId());
return true;
} else{
throw new PhyException(PhyException.Error,"账户信息或者密码不正确!!");
}
- 用户退出:
User user=(User)session.getAttribute("user");
if(user==null){
return false;
}
session.invalidate();
return false;
- 微信绑定、微信登录和解绑类似。
- 用户删除:
User user=(User)session.getAttribute("user");
if(user!=null){
if(ids.contains(user.getId())){
throw new PhyException(PhyException.HasEntity,"无法删除当前用户信息!!");
}
}
List<String> openIds=userService.findOpenIds(ids);
if(userService.delete(ids)){
if(openIds!=null&&openIds.size()>0){
ids.addAll(openIds);
}
userSessionRedisService.delBatch(ids);
return true;
}
return false;
- 权限过滤器:
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session=request.getSession();
String uriString = request.getRequestURI();
String uriMethod = request.getMethod();
String currSession=session.getId();
/*
* Http中允许接入的方法
*/
if(uriMethod.equals("GET") || uriMethod.equals("POST")||uriMethod.equals("DELETE")||uriMethod.equals("PUT")){
//游客
if(!(uriString.contains("/admin/")||uriString.contains("/common/"))){
logger.debug("游客用户登录!!");
chain.doFilter(request, response);
return;
}
User user=(User)session.getAttribute("user");
//用户未登录
if(user==null){
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return ;
}
String type=(String)session.getAttribute("loginType");
String sessionId=null;
if(type!=null&&type.equals("wechat")){
sessionId=userSessionRedisService.get(user.getOpenId());
}else{
sessionId=userSessionRedisService.get(user.getId());
}
//未登录系统
if(StrUtil.isBlank(sessionId)){
response.setStatus(510);
Map<String, Object> maps=new HashMap<String, Object>();
maps.put("code", PhyException.NoLogin);
maps.put("msg", "用户未登录系统!!");
session.invalidate();
response.getOutputStream().write(ReturnFormat.retParam(maps).getBytes());
return ;
}else if(!sessionId.equals(currSession)){//判断用户是否是同一个用户
response.setStatus(510);
session.invalidate();
Map<String, Object> maps=new HashMap<String, Object>();
maps.put("code", PhyException.HasMore);
maps.put("msg", "用户已经其他地方登录了!!");
response.getOutputStream().write(ReturnFormat.retParam(maps).getBytes());
return ;
}
switch(user.getRole()){
case Admin:
if(uriString.contains("/admin/")||uriString.contains("/common/")){
logger.debug("超级管理员登录!!");
chain.doFilter(req, res);
return;
}
case Common:
if(uriString.contains("/common/")){
logger.debug("普通管理员登录!!");
chain.doFilter(req, res);
return ;
}
}
//认证失败
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return ;
}
//禁止使用
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
- session监听器:
public void sessionCreated(HttpSessionEvent arg0) {
logger.info("User Session Create");
}
@Override
public void sessionDestroyed(HttpSessionEvent sessionEvent) {
//获取spring bean,session redis操作 bean
ApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(sessionEvent.getSession().getServletContext());
UserSessionRedisService userSessionRedisService = (UserSessionRedisService)wac.getBean("userSessionRedisServiceImpl");
//根据不同登录类型,删除redis中保存的session信息
HttpSession session=sessionEvent.getSession();
User user=(User)session.getAttribute("user");
String type=(String)session.getAttribute("loginType");
if(user!=null){
if(type!=null&&type.equals("wechat")){
userSessionRedisService.del(user.getOpenId(),session.getId());
}else{
userSessionRedisService.del(user.getId(),session.getId());
}
logger.info("User Session Destroy,userId:"+user.getId());
}
}