微服务——用户微服务单点登录

为什么要使用单点登录原理

链接:https://blog.csdn.net/weixin_45528987/article/details/105365115

架构图

在这里插入图片描述

看图可能还有点懵,下面贴过程与代码

第一步:在用户微服务下添加两个依赖

<!--jwt tokens生成工具-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
        </dependency>
        <!--redis缓存工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

第二步:application.yml配置文件配置redis与jjwt的配置

  redis:
    host: 127.0.0.1
token_name: token
jwt:
  config:
    key: searchroom #jwt言
    ttl: 360000 #jwt过期时间

用户登录时的代码逻辑

采用了手机号免注册的登录方式,当数据库中不存在此用户时创建用户,并且返回携带token的cookie。假如存在用户判断手机验证码是否正确,正确则返回token。其中token还要将token存入redis中。

代码中的一些只有变量名的名字即对应相对应的类。

/**
     * 手机验证登录
     * @param phone
     * @param smsCode
     * @return
     */
    @Override
    public ServiceResult loginByPhone(String phone, String smsCode, HttpServletRequest request){
        ServiceResult result = new ServiceResult();
        //当前时间
        Date date = new Date();
        User user = userMapper.selectByPhone(phone);
        //如果没有这个用户就创建此用户
        if (user == null && StringUtils.equals(smsCode, "123456")){
            User userCreater = new User();
            userCreater.setName(phone.substring(0,3)+"****"+phone.substring(7));
            userCreater.setPhoneNumber(phone);
            userCreater.setCreateTime(date);
            userCreater.setLastUpdateTime(date);
            userCreater.setLastLoginTime(date);
            userMapper.regiestUser(userCreater);
            return ServiceResult.seccess("登录成功", this.userIPAndSetRedis(userCreater, request));
        }else {
            //由于是手机号登录所以需要验证验证码
            if (StringUtils.equals(smsCode, "123456")){
                user.setLastLoginTime(date);
                userMapper.updateByPrimaryKeySelective(user);
                return ServiceResult.seccess("登录成功", this.userIPAndSetRedis(user, request));
            }else{
                result.setStatus(ServiceResult.Status.PARAMERROR.getCode());
                result.setMessage("验证码不正确");
            }
        }
        return result;
    }
    public String userIPAndSetRedis(User user, HttpServletRequest request){
        //生成令牌
        String token = jwtUtil.createJWT(String.valueOf(user.getId()), user.getPhoneNumber(), "");
        //获取用户真实ip地址
        String userIP = CusAccessObjectUtil.getIpAddress(request);
        System.out.println(userIP);
        //token存入redis中  key=token_userID
        //可以通过此实现但设备登录与防止token盗用的情况
        redisTemplate.opsForValue().set("token_"+user.getId(), userIP , 15, TimeUnit.MINUTES);
        return token;
    }

判断token是否过期或者存在盗用的风险

/**
     * 检测token是否过期,或者存在被盗用的情况,单设备登录
     * @param token
     * @return
     */
    @Override
    public ServiceResult checkToken(String token,HttpServletRequest request) {
        ServiceResult result = new ServiceResult();
        if (StringUtils.isBlank(token)){
            result.setStatus(ServiceResult.Status.PARAMERROR.getCode());
            result.setMessage("不能传空参数");
            return result;
        }
        try {
            //获取用户真实ip地址
            String userIP = CusAccessObjectUtil.getIpAddress(request);
            Claims claims = jwtUtil.parseJWT(token);
            Object value = redisTemplate.opsForValue().get("token_"+claims.getId());
            //判断是否token盗用
            if (!StringUtils.equals(String.valueOf(value), userIP)){
                result.setStatus(ServiceResult.Status.EXCEPTION.getCode());
                result.setMessage("token存在问题,请重新登录");
//                User user = userMapper.selectByPrimaryKey(Integer.valueOf(claims.getId()));
//                //短信通知用户他的登录地点方式可能存在风险
//                rabbitTemplate.convertAndSend("sms", user.getPhoneNumber());
                return result;
            }
            String username = claims.getSubject();
            return ServiceResult.seccess(username);
        }catch (Exception e){
            e.printStackTrace();
            result.setStatus(ServiceResult.Status.EXCEPTION.getCode());
            result.setMessage("登录已过期");
            return result;
        }
    }

在这里插入图片描述
在这里插入图片描述
登录成功后会自动跳转到首页的微服务工程的首页页面,看到前后域名会改变,cookie要注意不同域问题(跨域),这时候可以看到浏览器中存在名字为token的cookie。

我们浏览网站会发现,网站的域名是不会改变的,例如我们浏览开源中国,域名总为www.oschina.net,如何做到呢?
链接:
技术:https://blog.csdn.net/weixin_45528987/article/details/105385152
例子:https://blog.csdn.net/weixin_45528987/article/details/105392337

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Redis单点登录方案可以通过以下步骤实现: 1. 用户登录:用户在登录页面输入用户名和密码,向认证服务器发送登录请求。 2. 认证服务器校验:认证服务器校验用户名和密码是否正确,如果正确,生成一个唯一的Session ID作为标识用户身份,并将其存储到Redis中。同时,认证服务器将Session ID返回给客户端。 3. 客户端存储Session ID:客户端收到Session ID后,将其存储在Cookie中或者存储在本地,以便后续请求时使用。 4. 客户端向微服务发送请求:客户端向微服务发送请求时,在请求头或者请求参数中携带Session ID。 5. 微服务校验Session ID:微服务在接收到请求时,校验Session ID的有效性,如果有效,则返回资源给客户端;否则,返回401未授权状态码。 需要注意的是,为了保证Session ID的安全性,应该对Session ID进行加密处理。同时,为了减轻Redis的压力,应该设置Session ID的过期时间,避免不必要的资源浪费。 基于Redis单点登录方案具有以下优点: 1. 高性能:Redis一个高性能的内存数据库,可以快速地存储和查询Session ID信息。 2. 高可用性:Redis支持主从复制和哨兵机制,可以保证数据的高可用性和容错性。 3. 可扩展性:Redis可以通过集群部署来实现扩展,可以满足高并发的访问需求。 4. 易于实现:Redis提供了丰富的API和工具,可以方便地实现Session管理和过期处理。 需要注意的是,在使用Redis进行单点登录时,需要注意Redis的安全性和稳定性,避免Redis被攻击或者发生故障。因此,在部署和配置Redis时,需要采取安全措施和容错措施,以确保系统的安全性和可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值