微服务之用户注册与登录

用户注册逻辑:用户注册账号,输入姓名邮箱等信息注册后,后端就会发送邮件给用户邮箱。邮箱收到一个url,这个url信息中包含了用户名和uuid,点击后,也就是访问了激活的后端代码,后端将user表中的is_verfiy字段改成Y,完成验证 。
登陆的时候仅允许注册并激活的用户登陆。

注册时获取图片验证码的代码
CaptchaController:

package com.cskaoyan.gateway.controller.user;

/**
 * create by ciggar on 2020/04/05
 */

import com.mall.commons.result.ResponseData;
import com.mall.commons.result.ResponseUtil;
import com.mall.commons.tool.utils.CookieUtil;
import com.mall.user.IKaptchaService;
import com.mall.user.annotation.Anoymous;
import com.mall.user.constants.SysRetCodeConstants;
import com.mall.user.dto.KaptchaCodeRequest;
import com.mall.user.dto.KaptchaCodeResponse;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/user")
public class CaptchaController {

    @Reference(timeout = 3000, check = false)
    IKaptchaService kaptchaService;

    /**
     * 获取验证码
     */
    @Anoymous
    @GetMapping("/kaptcha")
    public ResponseData getKaptchaCode(HttpServletResponse response) {
        KaptchaCodeRequest kaptchaCodeRequest = new KaptchaCodeRequest();
        // 获取图片验证码
        KaptchaCodeResponse kaptchaCodeResponse = kaptchaService.getKaptchaCode(kaptchaCodeRequest);
        if (kaptchaCodeResponse.getCode().equals(SysRetCodeConstants.SUCCESS.getCode())) {
            // 生成一个cookie  key:kaptcha_uuid,value:uuid
            Cookie cookie = CookieUtil.genCookie("kaptcha_uuid", kaptchaCodeResponse.getUuid(), "/", 60);
            cookie.setHttpOnly(true);
            response.addCookie(cookie);
            return new ResponseUtil<>().setData(kaptchaCodeResponse.getImageCode());
        }
        return new ResponseUtil<>().setErrorMsg(kaptchaCodeResponse.getCode());
    }

    @Anoymous
    @PostMapping("/kaptcha")
    public ResponseData validKaptchaCode(@RequestBody String code, HttpServletRequest httpServletRequest) {
        KaptchaCodeRequest request = new KaptchaCodeRequest();
        String uuid = CookieUtil.getCookieValue(httpServletRequest, "kaptcha_uuid");
        request.setUuid(uuid);
        request.setCode(code);
        //  校验验证码
        // 通过uuid去获取验证码,和我们传过去的验证码对比,如果一致,验证成功,否则验证失败。
        KaptchaCodeResponse response = kaptchaService.validateKaptchaCode(request);
        if (response.getCode().equals(SysRetCodeConstants.SUCCESS.getCode())) {
            return new ResponseUtil<>().setData(null);
        }
        return new ResponseUtil<>().setErrorMsg(response.getCode());
    }
}

KaptchaServiceImpl:

package com.mall.user.services;

import com.mall.user.IKaptchaService;
import com.mall.user.constants.SysRetCodeConstants;
import com.mall.user.dal.entitys.ImageResult;
import com.mall.user.dto.KaptchaCodeRequest;
import com.mall.user.dto.KaptchaCodeResponse;
import com.mall.user.utils.ExceptionProcessorUtils;
import com.mall.user.utils.VerifyCodeUtils;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * ciggar
 * create-date: 2019/8/6-14:45
 */
@Slf4j
@Component
@Service
public class KaptchaServiceImpl implements IKaptchaService {

    @Autowired
    RedissonClient redissonClient;

    private final String KAPTCHA_UUID = "kaptcha_uuid";


    @Override
    public KaptchaCodeResponse getKaptchaCode(KaptchaCodeRequest request) {
        KaptchaCodeResponse response = new KaptchaCodeResponse();
        try {
            // 生成带验证码的图片,调用的一些Java和图形相关的API
            ImageResult capText = VerifyCodeUtils.VerifyCode(140, 43, 4);
            String uuid = UUID.randomUUID().toString();
            // 把k-v放入redis中,k:KAPTCHA_UUID+uuid,v:capText.getCode()
            RBucket rBucket = redissonClient.getBucket(KAPTCHA_UUID + uuid);
            rBucket.set(capText.getCode());
            log.info("产生的验证码:{},uuid:{}", capText.getCode(), uuid);
            // 设置过期时间
            rBucket.expire(120, TimeUnit.SECONDS);
            // 把验证码图片对象返回
            response.setImageCode(capText.getImg());
            response.setUuid(uuid);
            response.setCode(SysRetCodeConstants.SUCCESS.getCode());
            response.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
        } catch (Exception e) {
            log.error("KaptchaServiceImpl.getKaptchaCode occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    public KaptchaCodeResponse validateKaptchaCode(KaptchaCodeRequest request) {
        KaptchaCodeResponse response = new KaptchaCodeResponse();
        try {
            request.requestCheck();
            String redisKey = KAPTCHA_UUID + request.getUuid();
            RBucket<String> rBucket = redissonClient.getBucket(redisKey);
            String code = rBucket.get();
            log.info("请求的redisKey={},请求的code={},从redis获得的code={}", redisKey, request.getCode(), code);
            if (StringUtils.isNotBlank(code) && request.getCode().equalsIgnoreCase(code)) {
                response.setCode(SysRetCodeConstants.SUCCESS.getCode());
                response.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
                return response;
            }
            response.setCode(SysRetCodeConstants.KAPTCHA_CODE_ERROR.getCode());
            response.setMsg(SysRetCodeConstants.KAPTCHA_CODE_ERROR.getMessage());
        } catch (Exception e) {
            log.error("KaptchaServiceImpl.validateKaptchaCode occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }
}

  • 对称加密:

A给B传输数据m,在传输的过程中+e(加密),B收到了数据c后,-e(解密),获得数据m。
加密操作可能更复杂,如m*e+s。

  • 非对称加密:

A把传输数据给B,B首先生成两个具有相关新的数字e(公钥)和d(私钥)。
B把e传给A(以公开的方式), A通过e公钥的某个算法(例如+e)得到一个c(密文),并把c传给B(以公开的方式)。
A收到密文c后,通过密文求解原文的过程不是-e,而是-d(私钥),解得m(明文)。
也就是说加密时用e(公钥)进行加密,解密时用d(私钥)进行解密。

就算你知道e(公钥)和c(密文),你也不知道私钥,无法解密而获得m(明文)。

  • 下面来介绍一种最典型的非对称加密方式:RSA加密算法
  1. 要求B找出两个质数p、q。
  2. n = p * q
  3. f(n) = (p - 1) * (q - 1) (欧拉函数)
  4. 找出公钥e,1 < e < f(n) 且 e和f(n)互斥,在这个条件内随便找一个整数即可。
    找出私钥d,使得e*d/f(n)后的余数为1。

传输的数据是m
加密:m^e / n 求余数c
解密:c^d / n 求余数m(可以证明这个余数一定是m)。

这种算法的安全性如何呢?
传输中可能被截取的数据有:n、e、c
解密需要的数据:n、d、c
黑客要想解密就得根据e求出d,已知公式:e*d/f(n)后的余数为1。所以得知道f(n),要知道f(n)就得先知道p、q,要知道p、q就得对n进行质因数分解。
大数的质因数分解是很困难的。
RSA算法常用的n是1024位的二进制数,目前想分解这么大的数,普通计算机需要计算十年,量子计算机需要计算七天,所以银行系统都会定期进行更新。

你可能感兴趣的:(微服务)