SSO单点登录的理解和总结
单点登录是什么?
通俗的讲可以理解为:是一个系统登录,与其相关的系统模块就不用重复登录。
(登录一次就可以访问多个应用场景模块,减少重复登录,增加客户体验度)
SSO介绍
SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。它是目前比较流行的企业业务整合的解决方案之一。
## 传统登录方式存在的问题:
现象:因为通过nginx做负载均衡配置.当用户做敏感操作时,需要用户的权限的判断.所以需要动态的获取用户信息.如果将用户信息保存到Session对象中,则可能会出现用户频繁登陆的现象.因为Session不能共享,导致每个服务器都需要判断用户是否已经登陆.如果登录则继续跳转页面,如果没有登陆则跳转到登陆页面.
核心问题:因为服务器中的session不能共享!!!
单点登录实现
步骤:
- 用户通过浏览器访问jt-web中的登陆页面
- 当用户输入username/password后点击登陆按钮,开始进行校验.
- 通过httpClient形式将u/p发送到sso单点登录服务器.
- SSO接收用户传递的U/P之后开始校验.如果后台查询为null.则直接201返回,如果查询有数据.则表示U/P正确.根据加密算法+盐值生成token.当做key,再将user对象转化为JSON数据.当做value.之后保存到redis中.
如果上述的操作一切正常则返回200并且携带token返回. - jt-web解析返回值数据.如果返回值状态码201则表示用户名或密码错误.告知用户.
如果状态码200,则再次判断token数据是否为null.只有不为null时,则将数据正确返回.跳转页面.最后将token数据保存到客户端的COOKIE中.登录完成!!!
前台页面分析
用户url
页面JS
查看返回值
编辑前台Controller
/**
* 实现用户登陆
* 删除cookie cookie.setMaxAge(0);
* 会话关闭后删除 cookie.setMaxAge(-1)
* @param user
* @return
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult findUserByUP(User user,
HttpServletResponse response) {
try {
//一.用户信息发送到后台做校验
String token =
userService.findUserByUP(user);
//二.获取token数据,保存到cookie中
if(!StringUtils.isEmpty(token)) {
Cookie cookie = new Cookie("JT_TICKET", token);
cookie.setMaxAge(3600 * 24 * 7); //7天免密登录
cookie.setPath("/"); //表示当前网站根目录
response.addCookie(cookie); //将数据保存到Cookie中
return SysResult.oK();
}
} catch (Exception e) {
e.printStackTrace();
}
return SysResult.build(201,"用户登陆失败");
}
编辑前台Service
@Override
public String findUserByUP(User user) {
String url = "http://sso.jt.com/user/login";
Map<String,String> params
= new HashMap<String, String>();
params.put("username",user.getUsername());
params.put("password",DigestUtils.md5Hex(user.getPassword()));
String sysJSON = httpClient.doPost(url, params);
try {
SysResult sysResult =
objectMapper.readValue(sysJSON, SysResult.class);
//判断后台处理是否正确
if(sysResult.getStatus() == 200) {
//如果正确则返回token数据
return (String) sysResult.getData();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
编辑后台Controller
@RequestMapping("/login")
public SysResult findUserByUP(User user) {
try {
String token =
userService.findUserByUP(user);
if(!StringUtils.isEmpty(token)) {
return SysResult.oK(token);
}
} catch (Exception e) {
e.printStackTrace();
}
return SysResult.build(201,"用户登陆失败");
}
编辑后台Service
@Override
public String findUserByUP(User user) {
QueryWrapper<User> queryWrapper =
new QueryWrapper<User>(user);
User userDB = userMapper.selectOne(queryWrapper) ;
if(userDB != null) {
String str = "JT_TICKET"
+ System.currentTimeMillis()
+ user.getUsername();
//表示用户名和密码正确
String token =
DigestUtils.md5DigestAsHex(str.getBytes());
try {
String userJSON =
objectMapper.writeValueAsString(userDB);
//将数据保存到redis中
jedisCluster.setex(token,3600 * 24 * 7, userJSON);
return token;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
实现用户信息回显
页面分析
js分析
编辑后台Controller
//sso,利用ticket查询用户信息
@RequestMapping("/query/{ticket}")
public JSONPObject findUserByTicket(
@PathVariable String ticket,
String callback) {
String userJSON = jedisCluster.get(ticket);
return new JSONPObject(callback, SysResult.oK(userJSON));
}
用户登出操作
退出执行过程
- 如果用户点击退出按钮,则应该重定向到系统首页.
- 删除redis中数据.
- 删除cookie
- 介绍存储过程.(了解)
###页面分析
编辑UserController
//jt-web 使用用户登出操作
@RequestMapping("/logout")
public String logout(HttpServletRequest request,HttpServletResponse response) {
//1.获取cookie
Cookie[] cookies = request.getCookies();
String token = null;
for (Cookie cookie : cookies) {
if("JT_TICKET".equals(cookie.getName())) {
token = cookie.getValue();
break;
}
}
//2.删除redis
jedisCluster.del(token);
//3.删除cookie
Cookie cookie = new Cookie("JT_TICKET","");
cookie.setMaxAge(0);
cookie.setPath("/");
response.addCookie(cookie);
return "redirect:/index.html";
完成以上就OK了!