循序渐进之单点登录(3)--单点登陆基于Cookies

本文只是理一理思路

1. Server端

@RestController
@RequestMapping("userManager")
public class AuthrizeController {
    //登陆记录
    private static HashMap<String, String> accessRecord = new HashMap<>();

    @PostMapping("/login")
    public String login(String username, String password) {
        //登陆逻辑判断略
        //生成序列 过期时间等略
        String access = UUID.randomUUID().toString();
        String token = UUID.randomUUID().toString();
        accessRecord.put(token, access);
        return token + "," + access;
    }

    @GetMapping("/isLogin/{token}")
    public String isLogin(@PathVariable("token") String token) {
        if (accessRecord.containsKey(token)) {
            //只要有key 就代表登陆 返回access
            return accessRecord.get(token);
        } else {
            //没有登陆过  就返回404
            return "404";
        }
    }

}

2. Client端

使用restTemplate 调用认证中心服务接口

@RestController
@RequestMapping("/client")
public class SSOLoginController {

    @Autowired
    RestTemplate restTemplate;

    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password,
                        HttpServletRequest request, HttpServletResponse response) {

        // 向注册中心登陆
        HashMap<String, String> param = new HashMap<>();
        param.put("username", username);
        param.put("password", password);

        String ret = restTemplate.postForObject("http://127.0.0.1:8080/userManager/login", param, String.class);
        if (ret != null) {
            //返回值为acces
            // 登陆成功就 将login放入本地session
            String[] split = ret.split(",");
            String token = split[0];
            String access = split[1];
            // access 应该得设置过期时间
            request.getSession().setAttribute(token, access);
            response.addCookie(new Cookie("MyToken", token));
        }
        return "success";
    }

    // 用户拿着token来访问资源
    @GetMapping("/accessToClient")
    public String access(HttpServletRequest request, HttpServletResponse response) {

        String token = null;
        Cookie[] cookies = request.getCookies();
        for (int i = 0; i < cookies.length; i++) {
            if (cookies[i].getName().equals("MyToken")) {
                // 找出拿到token的
                token = cookies[i].getValue();
            }
        }
        if (null == token || "".equals(token)) {
            //token 不存在
            return "请先登陆,再来访问资源,重定向到登陆界面!";
        }
        //验证token是否有效
        //1. 本地 查找是否有token  session 并验证其有效性
        String access = (String) request.getSession().getAttribute(token);

        if (access != null) {
            return "访问到资源:123456";
        } else {
            //前往认证中心查找 是否再其他系统登陆过
            String ret = restTemplate.getForObject("http://127.0.0.1:8080/userManager/isLogin/" + token, String.class);
            if ("404".equals(ret)) {
                //认证中心 认为未登陆
                return "请先登陆,再来访问资源,重定向到登陆界面!";
            } else {
                //登陆 ,且返回 access
                request.getSession().setAttribute(token, ret);
                Cookie myToken = new Cookie("MyToken", token);
                myToken.setMaxAge(1);
                response.addCookie(myToken);
                return "访问到资源:123456";
            }
        }
    }
}

3. 启动项目

没有必要创建2个Client项目
在这里插入图片描述
允许并行执行就好了

在这里插入图片描述
每次启动,修改一下Client端的端口,避免端口冲突

4. 验证

  1. 先来尝试一下能否访问到
    在这里插入图片描述
    2.不能访问到就登陆
    在这里插入图片描述
    在这里插入图片描述
    3.换一个端口访问资源
    在这里插入图片描述
    成功访问到了

5. 实现原理

1.未登陆状态:
浏览器发来的请求里是不包含验证身份的Cookies的,那么来了就拦截,重定向到登陆页面
登陆,本地session注册一次,认证中心注册一次,这样不用每次来了都到认证中心查
2.登陆状态:

浏览器发来的请求里包含了验证身份的Cookies,cookie为(MyToken,token)
-> 从cookies里面找出MyToken
-> 用token在本地session查是否登陆过的记录,是否登陆了,登陆了直接放行
-> 未登陆,用传过来的token去认证中心查,是否再其他系统登陆了
-> 其他系统登陆了,在本地增加登陆记录,放行
-> 其他系统未登陆,重定向引导登陆

我实现的是 token -> access

本地和认证中心是否有access,代表登陆记录
access 可设置过期时间,等众多扩展

问题: 退出登陆问题
用户在系统一,系统二都留有本地登陆记录,如果在系统一退出登陆,再去访问系统二每次都会被放行怎么办?
解决:本地备份和认证中心 的access都设置过期时间就好了
系统二能访问也是一段时间内能访问

或者在退出的时候,往登陆的子系统发送退出消息,让他们注销本地记录也行

再者 所有系统公用缓存层,或者Session

以上个人拙见

6. 流程图

网上搜来的一张图:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值