1.单点登录
1.1.1 单点登录:
要求用户只登录一次,就可以实现免密登录(30天), 京淘项目的其他子系统也可以实现免密登录.。共享不能跨域去共享。
1.2 单点登录之前的准备
分析:
单点登录实现步骤:
1.用户输入用户名和密码点击登录 发送到JT-WEB服务器
2.JT-WEB服务器将数据发送到JT-SSO完成数据校验
3.JT-SSO 校验通过之后,保存到redis中 以TICKET-JSON 注意超时时间
4.当数据保存到redis中之后,将数据TICKET数据返回.
5.利用Cookie工具将数据保存
6.注意将Cookie设置为共享数据…
Cookie cookie = new Cookie("JT_TICKET",ticket);//定义cookie名字,ticket为值,这为动态
cookie.setMaxAge(30*24*60*60); //30天超时
cookie.setPath("/"); //设定cookie访问路径,cookie是在根路径,这样才能在其他访问之下可见,如果设置为/xxx,则只能在/xxx下可见
cookie.setDomain("jt.com"); //设定数据共享
response.addCookie(cookie); //上传Cookie,传给客户端。
return SysResult.success(); //登录成功之后返回
}
return SysResult.fail();
public SysResult doLogin(User user, HttpServletResponse response)
通过方法参数HttpServletResponse的response响应传cookie到客户端
1.2.1 页面URL分析
1.2.2 页面JS分析
位置
补充说明:返回值SysResult里面封装了status状态码等信息
2.完成单点登录
什么时候写cookie,登录成功之后才返回。
1.实现用户单点登录业务:
* 步骤:
1.接收用户名和密码 并且校验是否有效
2.将username和password发送到sso进行数据校验(完成的是远程调用,用@Reference标注下dubboUserService.查询)
3.判断ticket数据信息是否有效(登录成功的返回的是一个cookie)
4.如果ticket有效则将数据写入cookie
代码
2.1 编辑UserController
* url: http://www.jt.com/user/doLogin?r=0.4511522931461409
* 参数: username/password
* 返回值: SysResult对象
*
* cookie相同知识:
* http://xxx/addUser;
* http://xxx/aaa/addUser;
* 1.cookie.setPath("/aaa");
*
* 实现用户单点登录业务:
* 步骤:
* 1.接收用户名和密码 并且校验是否有效
* 2.将username和password发送到sso进行数据校验
* 3.判断ticket数据信息是否有效
* 4.如果ticket有效则将数据写入cookie
对页面消费者请求分析实现的位置
核心部分代码
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(User user, HttpServletResponse response){
//1.判断数据是否有效
if(StringUtils.isEmpty(user.getUsername()) || StringUtils.isEmpty(user.getPassword())){
return SysResult.fail();
}
//2.完成用户信息校验
String ticket = dubboUserService.findUserByUP(user);
//3.判断返回值是否有效
if(StringUtils.hasLength(ticket)){
//开始进行单点登录操作
Cookie cookie = new Cookie("JT_TICKET",ticket);
cookie.setMaxAge(30*24*60*60); //30天超时
cookie.setPath("/"); //设定cookie访问路径
cookie.setDomain("jt.com"); //设定数据共享
response.addCookie(cookie); //上传Cookie
return SysResult.success(); //登录成功之后返回
}
return SysResult.fail();
}
2.2 编辑UserService,对单点登录的实现类编辑(jt-sso里面),而单点的接口在分层提供生产者与消费者的中间接口的service里(commom).
下面为findUserByUP(user);在接口中的实现。业务调用
2.3 编辑的UserService实现类
/**
* 根据用户名和密码实现数据查询
* @param user
*
* @return
*/
@Override
public String findUserByUP(User user) {
//1.密码加密
String md5Pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(md5Pass);
//2.根据用户名和密码 查询数据 根据对象中不为null的属性当做where条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);//条件构造器
User userDB = userMapper.selectOne(queryWrapper);//根据用户名和密码得到结果只有一个,为了验证是否有值,进行后面判断
//3.判断用户信息是否有效
if(userDB == null){
//如果查询结果为null,则表示用户名或密码错误
return null;
}
//4.如果用户名和密码正确则开始单点登录操作,
String ticket = UUID.randomUUID().toString().replace("-", "");//取出UID的-,让别看不出是UID
//5.需要将用户数据转户为JSON 需要将数据进行脱敏处理setPassword,为安全,假数据,只是在页面展示,别人看不见真实的
userDB.setPassword("123456你试试!!!"); //假数据
String json = ObjectMapperUtil.toJSON(userDB);
//6.将数据保存到redis中 30天自动失效
int seconds = 30 * 24 * 60 * 60;//毫秒数
jedisCluster.setex(ticket, seconds, json);
return ticket;//返回真实秘钥ticket
}
2.3.1位置在这
2.3.2 对以上条件构造器说明,一般复杂写法为下![在这里插入图片描述](https://img-blog.csdnimg.cn/20210116113242850.png#pic_center)
2.3.3 简化传入User对象,之后返回也可以得到user和密码
2.3.4 开始登陆时,cookie的ticket票据存取
当单点校验正确,状态码为200,在3处为把用户信息存储到redis中,同时将ticket传回前端服务器,用户信息就存到cookie中。以后的访问,通过跨域去访问后端单点登录的服务器。单点登录服务器通过去redis获取ticket的信息,之后也是通过跨域的思想将数据返回。
2.3.5 在上述4正确情况下,我们为此登陆生成一个全球唯一UID。
在第6步,将数据保存到redis中说明
保存到redis使用对象redis的API中提供的jedisCluster对象
2.3.6 实现
此时即可登录成功,但是还没有实现登录回显,接下来进行回显实现
2.4 完成登录页面回显
sso里面有数据库的相关查询。
2.4.1 通过跨域
在web客户端页面js的ajax对cookie=JT_TICKET的访问位置
请求结果正确之后,进行相关操作,把服务器数据传回来,展现到页面
2.4.2 编辑jt-sso的userController
ticket存到缓存中了,要获取需要到redis中获取,注入JedisCluster
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private JedisCluster jedisCluster
/**
* 利用跨域实现JSONP请求
* URL地址:http://sso.jt.com/user/query/b3f042f1e29742ac8fe32655fa99d529?callback=jsonp1610592704700&_=1610592704737
* 参数: ticket信息
* 返回值结果: callback(SysResult对象)
*/
@RequestMapping("/query/{ticket}")
public JSONPObject findUserByTicket(@PathVariable String ticket,String callback){
String json = jedisCluster.get(ticket);
if(StringUtils.hasLength(json)){
return new JSONPObject(callback, SysResult.success(json));
}else{
//缓存中没有数据
return new JSONPObject(callback, SysResult.fail());
}
}
2.4.3 登录回显成功
2.5 退出登录
1.当用户点击退出按钮时,应该重定向到系统的首页. redirect:/xxxxxxx
2.删除Cookie中的数据
3.删除Redis中的数据
2.5.1 编辑CookieUtil
CookieUtil的位置,如果在jt-web下面写操作cookie的方法,由于代码量会增大,所以可以通过在单点登录处jt-sso加一个工具类util的API,位置
public class CookieUtils {
/**
* 1.保存cookie
* path: 一般都是/
* 删除cookie只需要把增cookie的seconds改为0就可以
*/
//操作对象响应response
public static void addCookie(HttpServletResponse response,String cookieName, String cookieValue, String domain, Integer seconds){
Cookie cookie = new Cookie(cookieName, cookieValue);//由于需要传的属性较多,可以使用封装一个对象,封装一个对象,把多个属性传过去
cookie.setDomain(domain);//设置共享路径
cookie.setMaxAge(seconds);//设置超时时间
cookie.setPath("/"); //
response.addCookie(cookie);//这里表示把对象cookie传进来,用addCookie进行存储
}
/**
* 2.获取cookie,获取是一种请求,而上面的存储设置是一种响应
*
*/
public static Cookie getCookie(HttpServletRequest request,String cookieName){
Cookie cookieTemp = null;
Cookie[] cookies = request.getCookies();//获取得到的是数组
if(cookies !=null && cookies.length > 0){//顺序不可以变换
for (Cookie cookie : cookies){//拿到之后进行遍历里面的属性
if(cookieName.equals(cookie.getName())){
cookieTemp = cookie;
break;
}
}
}
return cookieTemp;
}
/**
* 3.获取Cookie的值
*/
public static String getCookieValue(HttpServletRequest request,String cookieName){
Cookie cookie = getCookie(request,cookieName);
return cookie ==null?null:cookie.getValue();
}
}
2.5.2 jt-web下编辑UserControlle
位置:
核心代码
/**
* 用户退出操作
* url : http://www.jt.com/user/logout.html
* 返回值: 重定向到系统首页
* 实现步骤:
* 1. 从cookie中获取ticket信息
* 2. 删除Redis中的数据
* 3. 删除cookie中的记录
*/
@RequestMapping("logout")
public String logout(HttpServletRequest request,HttpServletResponse response){
//1. 1. 从cookie中获取ticket信息,调用CookieUtils.getCookieValue(请求是request对象,cookie的名字是"JT_TICKET")
String ticket = CookieUtils.getCookieValue(request, "JT_TICKET");
if(StringUtils.hasLength(ticket)){//判断是否有值,有值通过注入 jedisCluster,调用del删除
jedisCluster.del(ticket); //删除redis中的数据
//为什么传后面一堆?删除cookie必须与原始Cookie保持一致
CookieUtils.addCookie(response,"JT_TICKET","", "jt.com", 0);//删除cookie,这里也可以在jt-web上操作,值为"",注意不能写空null,而jt.com为共享路径,毫秒值0
}
//跳转系统首页
return "redirect:/";
}