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


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


相关推荐
Code季风1 小时前
深入理解微服务中的服务注册与发现(Consul)
java·运维·微服务·zookeeper·架构·go·consul
光军oi1 小时前
java微服务(Springboot篇)——————IDEA搭建第一个Springboot入门项目
java·spring boot·微服务
guojl2 小时前
RestTemplate使用手册
spring cloud·微服务
guojl2 小时前
RestTemplate原理分析
spring cloud·微服务
LCG元3 小时前
云原生微服务间的异步消息通信:最终一致性与系统容错的架构实战
微服务·云原生·架构
vim怎么退出6 小时前
万字长文带你了解微前端架构
前端·微服务·前端框架
幼稚园的山代王6 小时前
RabbitMQ 4.1.1初体验-队列和交换机
分布式·rabbitmq·ruby
小新学习屋6 小时前
Spark从入门到熟悉(篇三)
大数据·分布式·spark
沉着的码农10 小时前
【设计模式】基于责任链模式的参数校验
java·spring boot·分布式
小马爱打代码17 小时前
微服务外联Feign调用:第三方API调用的负载均衡与容灾实战
微服务·架构·负载均衡