• 随手记录第一话 -- Java中的单点登录都有哪些实现方式?


    1.单点登录介绍

    在早期开发中,一家公司可能只有一个Server,什么业务都写在一起,也就是早期的Servlet。
    随着业务的发展,逐渐的新增了很多的业务Server,这时候每个Server都要进行注册登录的话,那对用户来说简直是奔溃级的体验。
    一次注册、一次登录并不困难,但如果每次都登录,应该没什么用户会选择这个系列的产品了吧!

    2.何为单点登录?

    在业务满天飞的情况下,单点登录是比较流行的企业业务整合的解决方案之一。它的意义在于多个应用系统中,用户只需要登录一次即可访问所有相互信任的系统。

    3.实现猜想

    一次注册,一次登录,即可畅享所以系列的产品。那么难点在哪里?用户信息的共存共用才是单点登录的难点。首先从服务端和客户端来进行分析
    客户端SessionId和服务端Session
    凭借着客户端带过来的SessionId,在服务端Session中保存对应SessionId的用户信息,问题也很明显,Session是每个服务端私有的,并不是多个服务之间共用的

    那么单点登录实现的方式大概分为两种

    1. 客户端Cookie,也称为共享Cookie,将用户信息标识通过cookie存放,服务端直接从cookie中获取,这种不是很安全,很难管控
    2. token模式,所有应用系统共享一个身份认证系统。在首次认证成功后,为该用户生成唯一认证标识(token),客户端不管访问哪个服务均需要带上该认证标识,服务端获取到该标识可以通过(认证服务接口或者共用缓存、DB)获取到对应的用户信息即可。

    4.Java代码实现

    仅仅只是样例,并不能直接运行,这里使用的是Jwt作为token串,像早期的使用uuid也可以的

        static RedisManager redisManager;
    
        public static void main(String[] args) {
            //1. 登录
            //检验账号密码 状态什么的 。。。
    
            //2. 生成唯一token 返回给前端
            //授权
            List<GrantedAuthority> authorities = new ArrayList<>();
            // 昵称#id
            authorities.add(new SimpleGrantedAuthority("用户0002#2"));
            authorities.add(new SimpleGrantedAuthority(new Date().getTime() + ""));
            String token = JwtUtils.createToken("用户0002",authorities);
            log.info("返回前端token:{}",token);
    
            //3.存入缓存 这里使用缓存当做用户信息共享
            //存入 用户id -> token 校验是否已失效 也可以设置定期过期
            redisManager.set("MEMBER:TOKEN:2",token);
            //用户信息存储缓存 map 这里仅举例
            redisManager.hPut("MEMBER:INFO:2","nickname","用户002");
    
            //4.其他服务从头部获取token 再从缓存获取用户信息
    //        String token = getHeaderToken(request);
            Claims claims = JwtUtils.parseToken(token);
            List<Map<String,Object>> grantedAuthoritys = (List) claims.get(SecurityConstant.CLAIMS);
            String uid = null,nickname = null;
            for (Map<String, Object> map : grantedAuthoritys) {
                if(map.containsValue("#")){
                    String[] split = map.get("authority").toString().split("#");
                    uid = split[0];
                    nickname = split[1];
                    break;
                }
            }
            log.info("当前用户:{},{}",uid,nickname);
            //获取用户信息
            Map<Object, Object> userInfo = redisManager.hGetAll("MEMBER:INFO:2");
    
            //5.检验token过期 当前token可能是第二次登录生成的了 那么第一次登录的token应该要失效
            token += "1";
            String cacheToken = redisManager.get("MEMBER:TOKEN:2");
            if(cacheToken != null && !token.equals(cacheToken)) {
                log.info("当前token已失效:{}", token);
                //可直接报401
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    目标就是实现一次登录,多服务都可以获取到用户信息,第二次登录后,前面登录的token均失效,每个token只在当前登录次数有效

    5.优缺点

    1. 优点
    • 极大的提高了用户体验
    • 提高了开发的效率,除认证服务外减少了重复的认证代码
    • 简化了token的管理,让token只保存当次登录才有效的原则
    1. 缺点
    • 系统只认token不认操作用户,如果token泄漏的话,可能会导致一些重要信息被修改泄漏

    6.总结

    单点登录实现的难点,其实就是任意服务怎么实现根据token串获取用户信息共享,这里记录一下之前用到过的实现方式

    1. redis缓存,毫无疑问肯定是最常见的
    2. mongo、mysql等db存储,公共库
    3. 公共认证服务,内网远程调用

    如果还有其他的方式实现的,欢迎评论区留言哦

    以上就是本章的全部内容了。

    上一篇:SpringSecurity第一话 – 一文来吃透SpringSecurity+Jwt权限控制
    下一篇:随手记录第二话 – 高并发情况下秒杀、抢红包都有哪些实现方式?

    旧书不厌百回读,熟读精思子自知

  • 相关阅读:
    git第一次推送gitlab项目
    MySQL牛客题组练习
    【数据结构-图】有向无环图的应用
    学习笔记-Sysmon
    计算机网络的物理层 基本概念
    《MongoDB》MongoDB的简介与体系结构
    Logstash同步MySQL数据到ES
    你知道网警和黑客谁更厉害吗?看完这篇文章你就有答案了。
    你不知道的Event Loop
    linux + 宝塔 + django + websocket 部署
  • 原文地址:https://blog.csdn.net/qq_35551875/article/details/125855687