一.单点登录流程分析
1.客户端统一拦截过滤器
流程分析:
1.在对需要进行授权登录的url连接,访问统一被上放的过滤器流程所拦截
2.进入过滤器,首先判断当前域名下是否有cookie,如果存在,则判断该cookie的值作为key在redis中是否存在,如果存在则进入进行,不存在则进入服务端的登录授权界面.
3.如果当前域名下的cookie值不存在,则判断当前链接是否带有一个参数值为ticket的值,如果存在,则设置该值为cookie,然后重定向到本地址.
2.服务端流程
分析:
1.登录接口:用户名密码验证成功后,设置cookie,设置redis缓存,登录成功
2.登录页面:先判断是否有cookie以及redis缓存,如果满足,则重定向返回backurl以及附加参数ticket值为当前的cookie,如果不满足,则进入登录界面
3.退出登录:删除redis缓存,删除cookie
4.为了防止别人拿着带着ticket的链接去其他浏览器进行伪造登录,则可以对其ticket存入redis中,客户端对其进行一次性消费.
二.客户端与服务端cookie同步
1.js脚本更新
可通过html加入js脚本访问服务端,服务端再对其cookie重置时长
2.增长服务端cookie时长
可通过增长服务端cookie时长,如果客户端退出了,redis缓存将清理,再次访问服务端登录接口,服务端查询不到redis缓存,则对其cookie进行删除.但是这种不能算是完全意义上的同步.
三.关键代码
1.客户端过滤器filter
String cookieName = CookieUtil.getCookie(Constans.COOKIE_SSO, request);
if(cookieName!=null&& !cookieName.equals("")){
//验证cookie的有效性
User user = tokenManagerInter.getUserInfo(cookieName);
if(user!=null){
//验证成功,继续执行
//TODO 重置cookie时间,缓存时间
filterChain.doFilter(servletRequest,servletResponse);
}else {
//验证失败,删除无效cookie
CookieUtil.deleteCookie(Constans.COOKIE_SSO,response, "/");
//返回登录界面
String qstr = makeQueryString(request); // 将所有请求参数重新拼接成queryString
String backUrl=request.getRequestURL() + qstr; // 回调url
String location = "127.0.0.1/login?backUrl=" + URLEncoder.encode(backUrl, "utf-8");
response.sendRedirect(location);
}
}else {
String vtParam = pasreVtParam(request); // 从请求中
if (vtParam == null) {
// 请求中中没有vtParam,引导浏览器重定向到服务端执行登录校验
//返回登录界面
String qstr = makeQueryString(request); // 将所有请求参数重新拼接成queryString
String backUrl=request.getRequestURL() + qstr; // 回调url
String location = "127.0.0.1/login?backUrl=" + URLEncoder.encode(backUrl, "utf-8");
response.sendRedirect(location);
} else if (vtParam.length() == 0) {
// 有vtParam,但内容为空,表示到服务端loginCheck后,得到的结果是未登录
response.sendError(403);
} else {
// 让浏览器向本链接发起一次重定向,此过程去除vtParam,将vt写入cookie
redirectToSelf(vtParam);
}
}
2.服务端登录界面
先判断当前是否有cookie,如果没有,则进入登录界面,如果存在,则判断是否有redis缓存存在,如果不存在,则进入登录界面,如果存在,则重定向到backurl中去,同时带着ticket返回客户端
@Override
public String login(String backUrl, ModelMap map) {
String cookie = CookieUtil.getCookie(Constans.COOKIE_SSO, request);
//判断有无cookie
if(cookie==null){
//无cookie,进入登录界面
map.put("backUrl", backUrl);
return "login";
}else {
//当前存在cookie
if(tokenManagerInter.checkToken(cookie)){
//缓存存在
if (backUrl != null) {
try {
response.sendRedirect(StringUtils.appendUrlParameter(backUrl, Constans.PARAGRAM_VT, cookie));
} catch (IOException e) {
e.printStackTrace();
logger.error("登录重定向失败:"+e);
}
return null;
} else {
AccountUser user = tokenManagerInter.getUserInfo(cookie);
if(user!=null){
map.put("user", user);
}
map.put("vt", cookie);
return "loginSuccess";
}
}else {
//缓存不存在,删除cookie,返回登录界面
CookieUtil.deleteCookie(Constans.COOKIE_SSO,response,"/");
map.put("backUrl", backUrl);
return "login";
}
}
}
3.服务端登录接口
验证完用户名密码后设置cookie,增加redis缓存,重定向到backurl去.
//设置cookie
String uuid = UUID.randomUUID().toString().replaceAll("-","");
Cookie cookie = new Cookie(Constans.COOKIE_SSO, uuid);
cookie.setMaxAge(Constans.COOKIE_EXPIRE_TIME);//设置cookie时间
cookie.setPath("/");
response.addCookie(cookie);
//存入redis中
System.out.println("创建uuid:"+uuid);
accountUser.setUuid(uuid);
result.setModel(accountUser);
boolean creatToken = tokenManagerInter.createToken(accountUser);
System.out.println("创建token:"+creatToken);
if(!creatToken){
return resultUtil.setErrResult(ReturnCodeBase.ERR5002);
}
4.退出登录接口
退出登录时候,检查cookie是否存在,然后删除redis缓存,删除cookie,重定向到登录界面
String cookie = CookieUtil.getCookie(Constans.COOKIE_SSO, request);
if (cookie != null && !cookie.equals("")) {
tokenManagerInter.deleteToken(cookie);
CookieUtil.deleteCookie(Constans.COOKIE_SSO, response, "/");
}
if (backUrl != null && !backUrl.equals("")) {
try {
return "redirect:"+Constans.URL.PREFIX+"login?backUrl=" + URLEncoder.encode(backUrl, "utf-8");
} catch (UnsupportedEncodingException e) {
logger.error("退出登录重定向失败:" + e);
}
}
return "redirect:/login";