【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【20】认证服务04—SSO单点登录


持续学习&持续更新中…

守破离


【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【20】认证服务04—SSO单点登录

xxl-sso

https://gitee.com/xuxueli0323/xxl-sso
xxl-sso是开源的一个单点登录框架
一个分布式单点登录框架。只需要登录一次就可以访问所有相互信任的应用系统。 拥有"轻量级、分布式、跨域、Cookie+Token均支持、Web+APP均支持"等特性;。现已开放源代码,开箱即用。

C:\Windows\System32\drivers\etc\hosts(模仿三个域名)

#模拟单点登录
127.0.0.1 xxlssoserver.com
127.0.0.1 client1.com
127.0.0.1 client2.com

打包之前修改这三个的配置文件:

在这里插入图片描述

举例:修改客户端:

在这里插入图片描述

修改完成打包命令:(打包所有)

在这里插入图片描述

启动服务器
在这里插入图片描述

启动两个客户端:

在这里插入图片描述

在这里插入图片描述


自己测试:

C:\Users\lenovo\Desktop\xxl-sso\xxl-sso-server\target>java -jar xxl-sso-server-1.1.1-SNAPSHOT.jar
C:\Users\lenovo\Desktop\xxl-sso\xxl-sso-samples\xxl-sso-web-sample-springboot\target>java -jar xxl-sso-web-sample-springboot-1.1.1-SNAPSHOT.jar --server.port=13000
C:\Users\lenovo\Desktop\xxl-sso\xxl-sso-samples\xxl-sso-web-sample-springboot\target>java -jar xxl-sso-web-sample-springboot-1.1.1-SNAPSHOT.jar --server.port=12000

http://xxlssoserver.com:8080/xxl-sso-server/login
http://client1.com:12000/xxl-sso-web-sample-springboot/
http://client2.com:13000/xxl-sso-web-sample-springboot/

上面这三个地址,无论访问哪个都要求登录,并且一处登录,处处可用

多系统-单点登录

Single Sign On 一处登陆、处处可用(运行)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

单点登录流程原理图

在这里插入图片描述

单点登录流程简单实现

认证服务:ssoserver.com:8080

@Controller
public class LoginController {

    @Autowired
    StringRedisTemplate redisTemplate;

    /**
     * TODO 开放接口给其他系统,让它们用来查询 token 对应的用户信息,判断该用户是否登录过,实现单点登录
     */
    @ResponseBody
    @GetMapping("/userInfo")
    public String userInfo(@RequestParam("token") String token){
        String s = redisTemplate.opsForValue().get(token);
        return s;
    }

    @GetMapping("/login.html")
    public String loginPage(@RequestParam("redirect_url") String url, Model model,
                            @CookieValue(value = "sso_token",required = false) String sso_token){
        if(!StringUtils.isEmpty(sso_token)){
            //说明之前有人登录过,浏览器留下了痕迹
            return "redirect:"+url+"?token="+sso_token;
        }

        model.addAttribute("url",url);
        return "login";
    }

    @PostMapping("/doLogin")
    public String doLogin(@RequestParam("username") String username,
                          @RequestParam("password")String password,
                          @RequestParam("url")String url,
                          HttpServletResponse response){

		// 假设用户名密码不为空就登录成功
        if(!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)){
            //把登录成功的用户存起来。
            String uuid = UUID.randomUUID().toString().replace("-","");
            redisTemplate.opsForValue().set(uuid,username);
            // 给浏览器留下登录痕迹
            Cookie sso_token = new Cookie("sso_token",uuid);
            response.addCookie(sso_token);
            //登录成功,跳回之前页面,并带上token
            return "redirect:"+url+"?token="+uuid;
        }
        //登录失败,展示登录页
        return "login";
    }
}

客户端1:client1.com:8081

@Controller
public class HelloController {

    @Value("${sso.server.url}")
    String ssoServerUrl;

    /**
     * 无需登录就可访问
     * @return
     */
    @ResponseBody
    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }

    /**
     * TODO 如下判断,可以抽取出来放在一个Filter中,放在任何系统中,实现单点登录
     */
    /**
     * 感知这次是在 ssoserver 登录成功跳回来的。
     * @param model
     * @param session
     * @param token 只要去ssoserver登录成功跳回来就会带上
     * @return
     */
    @GetMapping("/employees")
    public String employees(Model model, HttpSession session,
                            @RequestParam(value = "token",required = false) String token){
        //
        if(!StringUtils.isEmpty(token)){
            //TODO 应该去ssoserver获取当前token真正对应的用户信息
            // 如果我们并不知道ssoserver的redis地址,也就是说客户端并不知道认证服务器将用户信息保存在哪里
            // 我们就得用令牌去认证服务器再查一次用户信息,查询用户信息成功,表明登录成功
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> forEntity = restTemplate.getForEntity("http://ssoserver.com:8080/userInfo?token=" + token, String.class);
            String body = forEntity.getBody();
            session.setAttribute("loginUser",body);
        }

        Object loginUser = session.getAttribute("loginUser");
        if(loginUser==null){
            //没登录,跳转到登录服务器进行登录
            //跳转过去以后,使用url上的查询参数标识我们自己是哪个页面
            //redirect_url=http://client1.com:8080/employees
            return "redirect:"+ssoServerUrl+"?redirect_url=http://client1.com:8081/employees";
        }else{
            List<String> emps = new ArrayList<>();
            emps.add("张三");
            emps.add("李四");

            model.addAttribute("emps",emps);
            return "list";
        }
    }
}

客户端2:client1.com:8082

@Controller
public class HelloController {

    @Value("${sso.server.url}")
    String ssoServerUrl;

    @GetMapping("/boss")
    public String boss(Model model, HttpSession session,
                            @RequestParam(value = "token",required = false) String token){
        if(!StringUtils.isEmpty(token)){
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> forEntity =
                    restTemplate.getForEntity("http://ssoserver.com:8080/userInfo?token=" + token, String.class);
            String body = forEntity.getBody();
            session.setAttribute("loginUser",body);
        }

        Object loginUser = session.getAttribute("loginUser");
        if(loginUser==null){
            return "redirect:"+ssoServerUrl+"?redirect_url=http://client2.com:8082/boss";
        }else{
            List<String> boss = new ArrayList<>();
            boss.add("666");
            boss.add("777");
            model.addAttribute("boss",boss);
            return "list";
        }
    }

}

参考

雷丰阳: Java项目《谷粒商城》Java架构师 | 微服务 | 大型电商项目.


本文完,感谢您的关注支持!


最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-09 17:58:01       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-09 17:58:01       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-09 17:58:01       58 阅读
  4. Python语言-面向对象

    2024-07-09 17:58:01       69 阅读

热门阅读

  1. git杂记

    git杂记

    2024-07-09 17:58:01      26 阅读
  2. [Python学习篇] Python面向对象——继承

    2024-07-09 17:58:01       29 阅读
  3. 【Linux命令入门】查找文件

    2024-07-09 17:58:01       23 阅读
  4. 编码与梦想:我的CSDN创作5周年

    2024-07-09 17:58:01       24 阅读
  5. 多数据库支持在PHP框架中的实现策略与实践

    2024-07-09 17:58:01       30 阅读
  6. JVM 堆内存分配过程

    2024-07-09 17:58:01       29 阅读
  7. c++单例模式的一种写法

    2024-07-09 17:58:01       25 阅读
  8. nunjucks动态更新模版路径

    2024-07-09 17:58:01       24 阅读
  9. 【python技巧】pytorch网络可视化

    2024-07-09 17:58:01       28 阅读