#单点登陆 #java #SSO

不说官话, 只说白话, 越白越好

统一名词

  • client1.com 第二个客户端
  • client2.com 第一个客户端
  • sso.com: 登录服务器域名
  • sso-token: sso.com域名下携带的token, 也就是说在sso.com下的服务器登录, sso.com域名下就会生成一个key为sso-token的cookie, 这个生成的行为, 皆由后端处理
  • 实现目的: 在client1或者client2其中之一登录了, 访问对方都可以直接访问, 实现一处登录, 处处访问

流程

1, 用户访问client1.com进行登录, 或者是资源client1.com/res,
访问资源肯定会被拦截到登录页面去 ,本示例以直接访问资源展开

浏览器访问: 
client1.com/res

2, client1后端肯定会做登录校验, client1Server后端处理

  • 校验用户是否登录, session里是否已经有了
  • 参数中是否有token令牌
    用户登录了, 就放行, 用户未登录, 重定向到sso.com的登录页面
public String example( HttpSession session,@RequestParam(value = "token",required = false) String token){
        if(!StringUtils.isEmpty(token)){
          //TODO 根据令牌, 发送http请求给ssoServer, 换取accessToken
          //比如: "http://sso.com/xx?token=" + token
        }
        //看看session里是否有登录用户
        Object loginUser = session.getAttribute("loginUser");
        if(loginUser == null){
            //跳转到登录服务器, 并且携带重定向页面
            //ssoServerUrl sso.com的登录页面
            //redirect_url: 登录成功之后, ssoServer需要回调你的页面
            return "redirect:"+ssoServerUrl+"?redirect_url="+redirect_url;
        }else{
            //TODO 用户已经登录, 去数据查询数据, 然后返回
        }
    }

3, 用户被重定向到了, sso.com的登录请求(ssoServerUrl) 不是直接访问了ssoServer的前端登录页面哈 ssoServer处理

 @GetMapping("/login.html")
    public String loginPage(
            @RequestParam("redirect_url") String url,
            Model model,
            @CookieValue(value = "sso_token",required = false) String ssoToken
    ) {
        if(!StringUtils.isEmpty(ssoToken)){
            //sso.com可以获取到cookie, 说明这个用户之前在别的地方(client1)登录过,
            return "redirect:"+url+"?token="+ssoToken;
        }
        model.addAttribute("url",url);
        return "login";
    }	

可以看到, 需要注意的是:

  • @CookieValue ssoToken 跳转到登录页面之前, 都会去先去当前域名下找一个叫sso_token的cookie, 如果这个值不是空的, 就会跳转到你重定向的页面, 就回到了第2步的位置, 这个也是实现sso的关键点

4, ssoServer验证用户没登录, 给用户重定向到sso.com的前端登录html页面 ssoServer
用户在这里输入账号密码, ssoServer进行登录

 @PostMapping("/doLogin")
    public String login(String username, String pwd, String url, HttpServletResponse response) {
        //url: 登录成功跳转, 跳回到之前访问的页面
        //TODO 实现你需要的登录逻辑, 验证账号密码, 防止csrf之类的
       
       // 重点:  这里有一个uid, 其实就是你这个用户信息的一个标识, 下次不管是谁来访问, 可以根据这个uid, 找到用户信息
       //但是这个uid并不代表就是用户信息, 是根据他去查询用户信息, 
       //比如这里可以将uid对应的用户信息, 放在redis里, 这样其他微服务也可以直接从redis里获取
       String uid = UUID.randomUUID().toString().replaceAll("-", "");
            redisTemplate.opsForValue().set(uid,username);
       
            //TODO 重点:  给当前服务器(ssoServer), 当前域名(sso.com),留一个cookie, 记录用户已经登录了
            //方便以后浏览器, 再访问sso.com的时候, 就会携带着这个cookie
            Cookie cookie  = new Cookie("sso_token",uid);
            response.addCookie(cookie);
            //然后携带令牌token, 重定向到client1.com去,注意这里没有用户信息, 只是一个登录的令牌
            return "redirect:"+url+"?token="+uid;
    }

5, 用户登录成功, 跳转到之前第一次访问的页面, client1.com/res client1Server
又跳到了第2步的代码里, 进行session验证, token验证, 用户是否已经登录, 成功就显示页面


接下来的步骤, 对用户无感,只是换了一个client2.com 但是角度从clientServer1变成了clientServer2
6, 用户浏览器访问client2.com/res

client2.com/res

7, client2Server接收到请求, 进行处理, 和第2步大体一样, client2Server

public String example( HttpSession session,@RequestParam(value = "token",required = false) String token){
        if(!StringUtils.isEmpty(token)){
          //TODO 根据令牌, 发送http请求给ssoServer, 换取accessToken
          //比如: "http://sso.com/xx?token=" + token
        }
        //看看session里是否有登录用户
        Object loginUser = session.getAttribute("loginUser");
        if(loginUser == null){
            //跳转到登录服务器, 并且携带重定向页面
            //ssoServerUrl sso.com的登录页面
            //redirect_url: 登录成功之后, ssoServer需要回调你的页面
            return "redirect:"+ssoServerUrl+"?redirect_url="+redirect_url;
        }else{
            //TODO 用户已经登录, 去数据查询数据, 然后返回
        }
    }

注意不一样的点是在于:

  • 用户登录了, 而且ssoServer里给sso.com域名下写了一个key为sso-token的cookie
  • 如上, 这时候, client2Server的example方法是可以接收到token的值的, 因此他可以直接使用这个token获取到用户信息

8, 重定向到client2.com/res页面, client2Server
返回/res的资源请求给用户, 和第5步一样

这样子, 单点登录是完成了,重要的点就是

  • ssoServer登录后, 得自己记录一个cookie, 相当于一个标识, 记录这个用户在这个浏览器上登录过, 他下次访问client2 的时候, 可以直接获取到这个令牌, 然后登录
  • client登录以后, 在session中也得存着这个标识, 因为他需要用这个标识去ssoServer获取用户信息

当然还是有很多安全考虑的, 要做的事情还很多, 比如令牌只能使用一次了, 加密了之类的, 反正大概就是这个样子了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值