单点登录实现策略
需求说明
要求用户只需要登录一次,那么就可以访问其他的认证系统,无需用户再次登录.
如果采用如下的配置,则必然会出现用户频繁登录的现象.
SSO介绍
单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的 一种登录方式
单点登录实现策略
步骤:
1.当用户输入用户名和密码时需要将数据传递给jt-web服务器进行登录操作.
2.jt-web服务器需要将数据传到jt-sso服务器中进行数据的校验.
3.jt-sso根据username/password查询数据库校验数据是否有效.
4.如果用户名和密码正确则将数据经过处理之后保存到redis中 KEY=UUID(每次生成的都不一样) VALUE=“userJSON”
5.如果用户写入redis成功,之后需要将用户的登录的凭证返回给客户端.
6.JT-WEB服务器将获取的TICKET信息保存到客户端的Cookie中,方便下次使用. 并且要求cookie共享的.
用户登录具体实现
用户登录页面分析
1.url分析
2.参数分析
3.页面JS分析
$.ajax({
type: "POST",
url: "/user/doLogin?r=" + Math.random(),
contentType: "application/x-www-form-urlencoded; charset=utf-8",
data: {username:_username,password:_password},
dataType : "json",
error: function () {
$("#nloginpwd").attr({ "class": "text highlight2" });
$("#loginpwd_error").html("网络超时,请稍后再试").show().attr({ "class": "error" });
$("#loginsubmit").removeAttr("disabled");
$this.removeAttr("disabled");
},
success: function (result) {
//如果数据不为null时执行
if (result) {
var obj = eval(result);
if (obj.status == 200) {
obj.success = "http://www.jt.com";
.....
编辑UserController
/**
* 完成用户的登录操作
* url地址:http://www.jt.com/user/doLogin?r=0.8989367429030823
* 参数: username/password
* 返回值: SysResult对象 的JSON的数据.
*
* cookie.setMaxAge(-1); 关闭浏览器会话时删除
* cookie.setMaxAge(0); 立即删除cookie
* cookie.setMaxAge(100); cookie可以存储的时间单位是秒
*
* http://www.jt.com/saveUser/xxx
* cookie.setPath("/");
* cookie.setPath("/add");
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(User user, HttpServletResponse response){
//1.实现用户的登录操作!!!
String ticket = dubboUserService.doLogin(user);
//2.校验ticket是否有值.
if(StringUtils.isEmpty(ticket)){
//用户名或者密码错误
return SysResult.fail();
}
//3.如果用户的ticket不为null,则表示登录正确,需要将数据保存到cookie中
//Cookie要求 1.7天有效 2.要求cookie可以在jt.com的域名中共享 3.cookie权限 /
Cookie cookie = new Cookie("JT_TICKET",ticket);
cookie.setMaxAge(7*24*3600);
cookie.setDomain("jt.com"); //在jt.com中实现页面共享.
cookie.setPath("/"); //定于cookie的权限根目录有效
response.addCookie(cookie); //利用response将cookie保存到客户端中.
return SysResult.success();
}
编辑UserServiceImpl
/**
* 1.根据用户名和密码查询数据库
* 2.校验用户数据的有效性.
* 3.如果用户的数据是正确的 则开始进行单点登录操作.
* 4.如果用户数据不正确 则ticket数据为null即可.
* @param user
* @return
*/
@Override
public String doLogin(User user) {
//1.将密码进行加密处理
String password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(password);
//如果传递的是对象,则根据对象中不为null的属性充当where条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
User userDB = userMapper.selectOne(queryWrapper);
//2.校验数据是否有效
if(userDB == null){
return null;
}
//userDB数据不为null,用户的输入信息正确.开启单点登录操作.
//3.1动态生成uuid
String ticket = UUID.randomUUID().toString().replace("-", "");
//3.2脱敏处理
userDB.setPassword("123456你信不??");
String userJSON = ObjectMapperUtil.toJSON(userDB);
//3.3 将数据保存到redis中
jedisCluster.setex(ticket, 7*24*60*60, userJSON);
return ticket;
}
数据校验
用户登录回显
当用户登录成功之后会生成COOKIE信息.根据cookie获取TICKET信息,之后根据ticket获取user信息,.之后在首页展现用户名称即可.
页面分析
1).页面url分析
2).页面JS分析
编辑JT-SSO UserController
/**
* 根据ticket信息查询用户的json信息 jsonp请求 返回值使用特定的对象封装.
* url地址:http://sso.jt.com/user/query/ca620491866a42e596b29ee52fc27aff?callback=jsonp1600333068471&_=1600333068521
*/
@RequestMapping("/query/{ticket}")
public JSONPObject findUserByTicket(@PathVariable String ticket, HttpServletResponse response,
String callback){
if(jedisCluster.exists(ticket)){
//可以正确返回
String userJSON = jedisCluster.get(ticket);
return new JSONPObject(callback, SysResult.success(userJSON));
}else{
//如果根据ticket查询有误,则应该删除Cookie信息.
Cookie cookie = new Cookie("JT_TICKET","");
cookie.setDomain("jt.com");
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
return new JSONPObject(callback, SysResult.fail());
}
}
用户登出操作
编辑UserController
/**
* 实现用户的登出操作 要求删除cookie 和redis中的数据(key)
* 步骤: 通过cookie获取ticket信息.
* url: http://www.jt.com/user/logout.html
* 参数: 暂时没有
* 返回值: 重定向到系统首页
*/
@RequestMapping("/logout")
public String logout(HttpServletRequest request,HttpServletResponse response){
Cookie[] cookies = request.getCookies();
if(cookies !=null && cookies.length >0){
for(Cookie cookie : cookies){
if("JT_TICKET".equals(cookie.getName())){
//获取value之后删除cookie
String ticket = cookie.getValue();
jedisCluster.del(ticket); //删除redis中的数据
//删除cookie时 必须与原来的cookie数据保持一致
cookie.setDomain("jt.com");
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
break;
}
}
}
return "redirect:/";
}
Cookie优化
package com.jt.util;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CookieUtil {
/**
* 该工具API主要的任务
* 1.根据cookie的名称 返回cookie对象
* 2.根据cookie的名称 返回valve的值
* 3.新增cookie方法
* 4.删除cookie方法
*/
public static Cookie getCookie(String cookieName, HttpServletRequest request){
Cookie[] cookies = request.getCookies();
if(cookies !=null && cookies.length >0) {
for (Cookie cookie : cookies) {
if (cookieName.equals(cookie.getName())) {
return cookie;
}
}
}
return null ;
}
public static String getCookieValue(String cookieName,HttpServletRequest request){
Cookie cookie = getCookie(cookieName, request);
return cookie ==null?null:cookie.getValue();
}
public static void addCookie(String cookieName, String cookieValue, String path,
String domain, int maxAge, HttpServletResponse response){
Cookie cookie = new Cookie(cookieName,cookieValue);
cookie.setPath(path);
cookie.setDomain(domain);
cookie.setMaxAge(maxAge);
response.addCookie(cookie);
}
public static void deleteCookie(String cookieName,String path,
String domain,HttpServletResponse response){
addCookie(cookieName,"",path, domain, 0, response);
}
}
重构用户登出操作
/**
* 实现用户的登出操作 要求删除cookie 和redis中的数据(key)
* 步骤: 通过cookie获取ticket信息.
* url: http://www.jt.com/user/logout.html
* 参数: 暂时没有
* 返回值: 重定向到系统首页
*/
@RequestMapping("/logout")
public String logout(HttpServletRequest request,HttpServletResponse response){
String ticket = CookieUtil.getCookieValue("JT_TICKET", request);
if(!StringUtils.isEmpty(ticket)){
//1.删除redis
jedisCluster.del(ticket);
//2.删除cookie
CookieUtil.deleteCookie("JT_TICKET", "/", "jt.com", response);
}
return "redirect:/";
/* Cookie[] cookies = request.getCookies();
if(cookies !=null && cookies.length >0){
for(Cookie cookie : cookies){
if("JT_TICKET".equals(cookie.getName())){
//获取value之后删除cookie
String ticket = cookie.getValue();
jedisCluster.del(ticket); //删除redis中的数据
//删除cookie时 必须与原来的cookie数据保持一致
cookie.setDomain("jt.com");
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
break;
}
}
}*/
}