【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【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

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

举例:修改客户端:

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

启动服务器

启动两个客户端:


自己测试:

bash 复制代码
C:\Users\lenovo\Desktop\xxl-sso\xxl-sso-server\target>java -jar xxl-sso-server-1.1.1-SNAPSHOT.jar
bash 复制代码
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
bash 复制代码
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

java 复制代码
@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

java 复制代码
@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

java 复制代码
@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架构师 | 微服务 | 大型电商项目.


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


相关推荐
Bug退退退1235 小时前
RabbitMQ 高级特性之死信队列
java·分布式·spring·rabbitmq
prince056 小时前
Kafka 生产者和消费者高级用法
分布式·kafka·linq
菜萝卜子7 小时前
【Project】基于kafka的高可用分布式日志监控与告警系统
分布式·kafka
Code季风10 小时前
深入理解微服务中的服务注册与发现(Consul)
java·运维·微服务·zookeeper·架构·go·consul
光军oi10 小时前
java微服务(Springboot篇)——————IDEA搭建第一个Springboot入门项目
java·spring boot·微服务
guojl11 小时前
RestTemplate使用手册
spring cloud·微服务
guojl11 小时前
RestTemplate原理分析
spring cloud·微服务
LCG元12 小时前
云原生微服务间的异步消息通信:最终一致性与系统容错的架构实战
微服务·云原生·架构
vim怎么退出14 小时前
万字长文带你了解微前端架构
前端·微服务·前端框架
幼稚园的山代王15 小时前
RabbitMQ 4.1.1初体验-队列和交换机
分布式·rabbitmq·ruby