投票项目_登录功能的版本迭代

V0版本:

        实现最简单的登录,写个接口去数据库查有没有前端传来的账号和密码,查到且密码正确返回“登录成功”,其余情况统一返回“账号或密码错误”。

V1版本:

        用session代替cookie 先导入依赖,将session加入到redis中

        1.导入依赖

        

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

        2. 设置拦截器

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String requestURI = request.getRequestURI();
        log.info("拦截到请求requestURI:{}", requestURI);
        // 这里可以使用false来避免自动创建新的空会话
        HttpSession session = request.getSession();
        // 检查用户是否已登录
        if (session != null && session.getAttribute("userId") != null) {
            // 用户已登录
            log.info("用户已登录放行");
            return true;
        } else {
            // 用户未登录
            log.info("用户未登录,以跳转到登录页面");
            response.setStatus(401);
            response.sendRedirect("http://localhost:8080/login.html");
            return false; // 终止请求处理
        }

    }

}

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") // 拦截所有
                //选择排除不需要拦截的地址
                .excludePathPatterns("/login","/login.html","/regist","/regist.html");
    }
}

        3. 给session加一个userId字段,用于拦截器的处理

        HttpSession session = request.getSession();
        session.setAttribute("userId", dbUser.getId());
        System.out.println("Session中创建的userId:" + session.getAttribute("userId"));

V2版本:

        对前端传来的密码进行加盐和加密处理

        String password = loginDTO.getPassword();
        String userSalt = dbUser.getSalt();
        String DBpassword = dbUser.getPassword();
        String saltPassword = password+userSalt;
        String md5SaltPwd = DigestUtils.md5DigestAsHex(saltPassword.getBytes());
        if(!md5SaltPwd.equals(DBpassword)){
            return  R.error("用户名或者密码错误");
        }

V3版本:

        1. 生成验证码的工具类

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import javax.imageio.ImageIO;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.Random;


public class ValidateCodeUtil {
    private static Random random = new Random();
    private int width = 165; //验证码的宽
    private int height = 45; //验证码的高
    private int lineSize = 30; //验证码中夹杂的干扰线数量
    private int randomStrNum = 4; //验证码字符个数

    private String randomString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ";
    private final String sessionKey = "JCCODE";

    //字体的设置
    private Font getFont() {
        return new Font("Times New Roman", Font.ROMAN_BASELINE, 40);
    }

    //颜色的设置
    private static Color getRandomColor(int fc, int bc) {

        fc = Math.min(fc, 255);
        bc = Math.min(bc, 255);

        int r = fc + random.nextInt(bc - fc - 16);
        int g = fc + random.nextInt(bc - fc - 14);
        int b = fc + random.nextInt(bc - fc - 12);

        return new Color(r, g, b);
    }

    //干扰线的绘制
    private void drawLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(20);
        int yl = random.nextInt(10);
        g.drawLine(x, y, x + xl, y + yl);

    }

    //随机字符的获取
    private  String getRandomString(int num){
        num = num > 0 ? num : randomString.length();
        return String.valueOf(randomString.charAt(random.nextInt(num)));
    }

    //字符串的绘制
    private String drawString(Graphics g, String randomStr, int i) {
        g.setFont(getFont());
        g.setColor(getRandomColor(108, 190));
        //System.out.println(random.nextInt(randomString.length()));
        String rand = getRandomString(random.nextInt(randomString.length()));
        randomStr += rand;
        g.translate(random.nextInt(3), random.nextInt(6));
        g.drawString(rand, 40 * i + 10, 25);
        return randomStr;
    }


    //生成随机图片
    public void getRandomCodeImage(HttpServletRequest request, HttpServletResponse response){
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();
        g.fillRect(0, 0, width, height);
        g.setColor(getRandomColor(105, 189));
        g.setFont(getFont());
        // 干扰线
        for (int i = 0; i < lineSize; i++) {
            drawLine(g);
        }
        // 随机字符
        String randomStr = "";
        for (int i = 0; i < randomStrNum; i++) {
            randomStr = drawString(g, randomStr, i);
        }
        System.out.println("随机字符:"+randomStr);
        g.dispose();
        //移除之前的session中的验证码信息
        session.removeAttribute(sessionKey);
        //重新将验证码放入session
        session.setAttribute(sessionKey, randomStr);
        try {
            //  将图片以png格式返回,返回的是图片
            ImageIO.write(image, "PNG", response.getOutputStream());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }




    //生成随机图片的base64编码字符串
    public String getRandomCodeBase64(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();
        g.fillRect(0, 0, width, height);
        g.setColor(getRandomColor(105, 189));
        g.setFont(getFont());
        //干扰线
        for (int i = 0; i < lineSize; i++) {
            drawLine(g);
        }

        //随机字符
        String randomStr = "";
        for (int i = 0; i < randomStrNum; i++) {
            randomStr = drawString(g, randomStr, i);
        }
        System.out.println("随机字符:"+randomStr);
        g.dispose();
        session.removeAttribute(sessionKey);
        session.setAttribute(sessionKey, randomStr);
        String base64String = "";
        try {
            //  直接返回图片
            //  ImageIO.write(image, "PNG", response.getOutputStream());
            //返回 base64
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ImageIO.write(image, "PNG", bos);

            byte[] bytes = bos.toByteArray();
            Base64.Encoder encoder = Base64.getEncoder();
            base64String = encoder.encodeToString(bytes);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return base64String;
    }

}

        2. 基于工具类的方法类

import com.example.votedemo.common.ValidateCodeUtil;
import com.google.common.util.concurrent.RateLimiter;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;


@RestController
public class ValidateCodeController {

    //返回验证码图片
    @GetMapping("/getCaptchaImg")
    public void getCaptchaImg(HttpServletRequest request, HttpServletResponse response, HttpSession session) {

        try {

            response.setContentType("image/png");
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Expire", "0");
            response.setHeader("Pragma", "no-cache");
            ValidateCodeUtil validateCode = new ValidateCodeUtil();
            // getRandomCodeImage方法会直接将生成的验证码图片写入response
            validateCode.getRandomCodeImage(request, response);
            // System.out.println("session里面存储的验证码为:"+session.getAttribute("JCCODE"));

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 验证码校验
    @GetMapping("/checkCaptcha")
    @ApiOperation("验证码校验接口")
    public boolean getCheckCaptcha(@RequestParam("code") String code, HttpSession session) {

        try {
            //toLowerCase() 不区分大小写进行验证码校验
            String sessionCode= String.valueOf(session.getAttribute("JCCODE")).toLowerCase();
            System.out.println("session里的验证码:"+sessionCode);
            String receivedCode=code.toLowerCase();
            System.out.println("用户的验证码:"+receivedCode);
            return !sessionCode.equals("") && !receivedCode.equals("") && sessionCode.equals(receivedCode);

        } catch (Exception e) {

            return false;
        }

    }

    // 例如,创建一个每秒允许生成1个验证码的限流器
    RateLimiter rateLimiter = RateLimiter.create(1.0); // 参数表示每秒令牌生成速率
    // 生成验证码,返回的是 base64
    @GetMapping("/getCaptchaBase64")
    @ApiOperation("返回base64验证码接口")
    public Object getCaptchaBase64(HttpServletRequest request, HttpServletResponse response) {
        if (!rateLimiter.tryAcquire()) {
            // 如果获取令牌失败(即超过限流阈值)
            Map<String, String> result = new HashMap<>();
            result.put("message", "请求过于频繁,请稍后再试");
            return result;
        }
        Map result = new HashMap();
        try {
            response.setContentType("image/png");
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Expire", "0");
            response.setHeader("Pragma", "no-cache");
            ValidateCodeUtil validateCode = new ValidateCodeUtil();
            // 返回base64
            String base64String = validateCode.getRandomCodeBase64(request, response);
            result.put("url", "data:image/png;base64," + base64String);
            result.put("message", "created successfull");
            //http://tool.chinaz.com/tools/imgtobase/  base64直接转为图片网站
            System.out.println("结果:" + result.get("url"));
        } catch (Exception e) {
            System.out.println(e);
        }

        return result;
    }

}

        3. 功能使用

    @Autowired
    ValidateCodeController validateCodeController;
    
    @PostMapping("/login")
    @Transactional
    @ApiOperation("用户登录接口")
    public R<String> login(@RequestBody LoginDTO loginDTO, HttpServletRequest request){
        // 登录
        // 先进行验证码校验
        boolean captchaVerified = validateCodeController.getCheckCaptcha(loginDTO.getCaptcha(), request.getSession());
        if (!captchaVerified) {
            return R.error("验证码错误");
        }
        ......

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值