企业级电商C端游客/会员全场景登录注册模块方案

35 阅读8分钟

核心需求复述

你需要基于SpringCloud微服务架构,为企业电商系统设计一套覆盖C端游客/会员全场景的登录注册模块方案,要求方案完整、思路落地性强,能适配电商业务中登录注册的各类实际场景(如游客转正、多方式登录、登录态管理等)。

一、整体架构设计(SpringCloud环境)

1. 微服务拆分(核心服务边界)

基于“高内聚、低耦合”原则,将登录注册模块拆解为以下微服务(以SpringCloud Alibaba为例):

服务名称核心职责
user-center核心服务:用户注册、登录、身份校验、游客转正、用户基础信息管理
auth-server认证授权:JWT Token生成/验证、刷新Token、多端登录态管理
notify-service通知服务:短信/邮箱验证码发送、登录提醒、注册成功通知
oauth-service第三方登录:对接微信/支付宝/QQ等第三方账号授权、账号绑定
gateway网关服务:接口统一入口、限流、鉴权、路径转发(拦截未登录请求)

2. 核心技术栈选型

技术/组件用途
SpringCloud Alibaba微服务基座(Nacos:注册/配置中心;Sentinel:限流;Seata:分布式事务)
Spring Security + JWT认证授权(Token生成/验证、权限控制)
Redis缓存验证码、登录Token、游客临时数据、限流计数
MySQL + MyBatis-Plus用户数据存储、CRUD(支持分库分表)
BCrypt密码不可逆加密
OpenFeign微服务间接口调用(如user-center调用notify-service发验证码)

二、核心业务场景与实现思路

1. 基础数据模型设计(核心表)

-- 用户核心表(区分游客/会员)
CREATE TABLE user_info (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id VARCHAR(64) NOT NULL COMMENT '用户唯一标识(雪花算法)',
    mobile VARCHAR(11) UNIQUE COMMENT '手机号(会员必填)',
    email VARCHAR(64) UNIQUE COMMENT '邮箱',
    password VARCHAR(128) COMMENT '密码(BCrypt加密)',
    nickname VARCHAR(64) COMMENT '昵称(游客可随机生成)',
    avatar VARCHAR(255) COMMENT '头像',
    user_type TINYINT NOT NULL DEFAULT 0 COMMENT '0-游客 1-会员',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '1-启用 0-禁用',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_mobile (mobile),
    INDEX idx_user_id (user_id)
) COMMENT 'C端用户信息表';

-- 验证码表(防重复/过期)
CREATE TABLE verify_code (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    target VARCHAR(64) NOT NULL COMMENT '手机号/邮箱',
    code VARCHAR(6) NOT NULL COMMENT '6位验证码',
    type TINYINT NOT NULL COMMENT '1-注册 2-登录 3-找回密码',
    expire_time DATETIME NOT NULL COMMENT '过期时间(5分钟)',
    status TINYINT NOT NULL DEFAULT 0 COMMENT '0-未使用 1-已使用',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_target_type (target, type)
) COMMENT '验证码记录表';

-- 登录日志表(安全审计)
CREATE TABLE login_log (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id VARCHAR(64) NOT NULL,
    login_type TINYINT NOT NULL COMMENT '1-手机号验证码 2-密码 3-第三方',
    device VARCHAR(32) COMMENT 'PC/APP/H5',
    ip VARCHAR(32) COMMENT '登录IP',
    login_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    logout_time DATETIME COMMENT '登出时间',
    INDEX idx_user_id (user_id)
) COMMENT '用户登录日志表';

-- 第三方绑定表
CREATE TABLE oauth_bind (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id VARCHAR(64) NOT NULL,
    oauth_type TINYINT NOT NULL COMMENT '1-微信 2-支付宝 3-QQ',
    oauth_openid VARCHAR(64) NOT NULL COMMENT '第三方唯一标识',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_oauth_type_openid (oauth_type, oauth_openid),
    INDEX idx_user_id (user_id)
) COMMENT '第三方账号绑定表';

2. 核心场景实现

场景1:游客身份处理(未登录)

电商场景中游客需支持“浏览商品、加购、收藏”等基础操作,核心思路:

  • 游客无身份验证,后端生成临时user_id(雪花算法)+ 临时Token(JWT,有效期2小时);
  • 游客的购物车、收藏等数据通过临时user_id关联存储(购物车服务/收藏服务);
  • 下单前强制引导登录/注册,触发“游客转正”流程。
场景2:会员注册(手机号为主流)

核心流程:获取验证码 → 校验验证码 → 注册入库,具体实现:

// user-center 核心代码示例(注册接口)
@RestController
@RequestMapping("/api/user")
@Slf4j
public class UserRegisterController {
    @Autowired
    private VerifyCodeService verifyCodeService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    // 1. 发送注册验证码
    @PostMapping("/send-register-code")
    public ResultVO sendRegisterCode(@RequestParam String mobile) {
        // 步骤1:参数校验(手机号格式)
        if (!RegexUtils.isMobile(mobile)) {
            return ResultVO.error(10001, "手机号格式错误");
        }
        // 步骤2:限流(同一手机号1分钟内最多1次)
        String limitKey = "send_code_limit:" + mobile;
        if (redisTemplate.hasKey(limitKey)) {
            return ResultVO.error(10002, "验证码发送过于频繁,请稍后再试");
        }
        // 步骤3:生成6位验证码
        String code = RandomUtils.generate6DigitCode();
        // 步骤4:缓存验证码(Redis,5分钟过期)
        String codeKey = "verify_code:register:" + mobile;
        redisTemplate.opsForValue().set(codeKey, code, 5, TimeUnit.MINUTES);
        // 步骤5:记录验证码到数据库
        verifyCodeService.saveVerifyCode(mobile, code, 1); // 1=注册类型
        // 步骤6:调用notify-service发送短信(OpenFeign)
        notifyService.sendSms(mobile, "【XX电商】您的注册验证码是:" + code + ",5分钟内有效");
        // 步骤7:设置限流缓存(1分钟)
        redisTemplate.opsForValue().set(limitKey, "1", 1, TimeUnit.MINUTES);
        return ResultVO.success("验证码发送成功");
    }

    // 2. 提交注册
    @PostMapping("/register")
    public ResultVO register(@RequestBody RegisterDTO registerDTO) {
        // 步骤1:参数校验
        String mobile = registerDTO.getMobile();
        String code = registerDTO.getCode();
        String password = registerDTO.getPassword();
        if (StringUtils.isAnyBlank(mobile, code, password)) {
            return ResultVO.error(10003, "参数不能为空");
        }
        // 步骤2:校验验证码
        String codeKey = "verify_code:register:" + mobile;
        String cacheCode = redisTemplate.opsForValue().get(codeKey);
        if (cacheCode == null || !cacheCode.equals(code)) {
            return ResultVO.error(10004, "验证码错误或已过期");
        }
        // 步骤3:校验手机号是否已注册
        if (userInfoService.existsByMobile(mobile)) {
            return ResultVO.error(10005, "手机号已注册");
        }
        // 步骤4:密码加密(BCrypt)
        String encryptPwd = BCrypt.hashpw(password, BCrypt.gensalt());
        // 步骤5:插入用户表(会员)
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(SnowFlakeUtil.generateId()); // 雪花算法生成唯一ID
        userInfo.setMobile(mobile);
        userInfo.setPassword(encryptPwd);
        userInfo.setNickname("用户" + mobile.substring(7)); // 默认昵称
        userInfo.setUserType(1); // 1=会员
        userInfoService.save(userInfo);
        // 步骤6:清理验证码缓存+标记验证码为已使用
        redisTemplate.delete(codeKey);
        verifyCodeService.markCodeUsed(mobile, code, 1);
        return ResultVO.success("注册成功", userInfo.getUserId());
    }
}
场景3:多方式登录(适配电商核心场景)
登录方式核心流程
手机号+验证码校验验证码 → 查找用户(不存在则自动注册为会员)→ 生成Token → 记录登录日志
账号密码查找用户 → BCrypt校验密码 → 生成Token → 记录登录日志
第三方登录(微信)前端获取微信code → 后端换openid → 查绑定关系(已绑定:生成Token;未绑定:创建会员+绑定)
游客临时登录生成临时user_id → 生成临时Token → 返回给前端(无身份校验)

核心登录代码示例(手机号+验证码)

@PostMapping("/login-by-code")
public ResultVO loginByCode(@RequestBody LoginByCodeDTO loginDTO) {
    String mobile = loginDTO.getMobile();
    String code = loginDTO.getCode();
    // 1. 校验验证码(同注册逻辑)
    String codeKey = "verify_code:login:" + mobile;
    String cacheCode = redisTemplate.opsForValue().get(codeKey);
    if (cacheCode == null || !cacheCode.equals(code)) {
        return ResultVO.error(10006, "验证码错误或已过期");
    }
    // 2. 查找用户(不存在则自动注册)
    UserInfo userInfo = userInfoService.getByMobile(mobile);
    if (userInfo == null) {
        // 自动注册为会员(简化流程)
        userInfo = new UserInfo();
        userInfo.setUserId(SnowFlakeUtil.generateId());
        userInfo.setMobile(mobile);
        userInfo.setNickname("用户" + mobile.substring(7));
        userInfo.setUserType(1);
        userInfoService.save(userInfo);
    }
    // 3. 生成JWT Token(access_token+refresh_token)
    AuthTokenDTO tokenDTO = authService.generateToken(userInfo.getUserId(), userInfo.getUserType());
    // 4. 记录登录日志(异步处理,避免阻塞)
    loginLogService.asyncSaveLoginLog(userInfo.getUserId(), 1, loginDTO.getDevice(), loginDTO.getIp()); // 1=手机号验证码登录
    // 5. 清理验证码缓存
    redisTemplate.delete(codeKey);
    return ResultVO.success("登录成功", tokenDTO);
}
场景4:登录态管理(电商核心诉求)
  • Token刷新:access_token(2小时)过期前,前端调用/api/user/refresh-token接口,传入refresh_token(7天有效期),后端校验后生成新的access_token;
  • 多端登录:Redis中存储user_id:devices(key)→ 设备+Token列表(value),支持“查看登录设备、强制下线某设备(删除对应Token)”;
  • 自动登录:前端勾选“记住我”时,refresh_token有效期延长至30天,下次打开APP自动刷新access_token。
场景5:游客转正(电商核心场景)

游客下单前需转正为会员,核心是合并临时数据,流程:

  1. 游客触发登录/注册后,前端传入“游客临时user_id”和“会员Token”;
  2. 后端校验会员身份 + 游客临时数据有效性;
  3. 调用购物车服务/收藏服务,将游客的临时购物车、收藏数据合并到会员账号;
  4. 更新用户表中游客的user_type为“会员”,失效游客临时Token;
  5. 返回合并成功,引导用户继续下单。

3. 安全设计(电商必备)

  • 密码安全:BCrypt不可逆加密,禁止明文存储;
  • 验证码安全:限流、Redis缓存防重复使用、5分钟过期;
  • Token安全:JWT签名(防止篡改)、Redis存储Token(便于注销/强制下线)、HTTPS传输;
  • 接口安全:网关层做XSS/CSRF防护、重要接口加签名校验;
  • 数据安全:用户敏感信息脱敏(如手机号显示138****1234)、数据库字段加密(手机号/邮箱)。

4. 性能优化

  • 缓存:验证码、Token、用户基础信息存入Redis,减少DB查询;
  • 限流:Sentinel对登录/注册/发送验证码接口限流(如QPS=1000),防止恶意攻击;
  • 异步:登录日志、短信发送等非核心逻辑用@Async异步处理;
  • 分库分表:用户量达千万级时,对user_info表按user_id分表(如按尾号分10张表)。

三、总结

核心关键点回顾

  1. 架构层面:基于SpringCloud拆分用户中心、认证、通知等微服务,职责单一,便于扩展;
  2. 业务层面:覆盖游客/会员全生命周期(临时登录→注册→正式登录→转正),适配电商多方式登录场景;
  3. 安全&性能:通过Redis缓存、限流、密码加密、异步处理,兼顾安全性和高并发能力;
  4. 落地性:数据模型、核心代码可直接复用,适配企业级电商系统的实际业务需求。

这套方案既满足了C端用户登录注册的基础需求,又适配了电商场景的特殊诉求(游客转正、多端登录、安全审计),同时符合SpringCloud微服务的最佳实践,可直接落地到实际项目中。