用户登录后端:登录密码解密后用PasswordEncoder验证密码是否正确

前置知识:
前端登录加密看用户登录
PasswordEncoder加密看PasswordEncoder详解

项目中因为要判断用户登录密码是否正确,通过输入错误次数锁住用户

1.后端配置rsa私钥

#密码加密传输,前端公钥加密,后端私钥解密
rsa:
  private_key: xxxx

2. 读取配置文件

/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.njry.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author Zheng Jie
 * @website https://eladmin.vip
 * @description
 * @date 2020-05-18
 **/
@Data
@Component
public class RsaProperties {

    public static String privateKey;

    @Value("${rsa.private_key}")
    public void setPrivateKey(String privateKey) {
        RsaProperties.privateKey = privateKey;
    }
}

3. Rsa 工具类

package com.njry.utils;

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author https://www.cnblogs.com/nihaorz/p/10690643.html
 * @description Rsa 工具类,公钥私钥生成,加解密
 * @date 2020-05-18
 **/
public class RsaUtils {

    private static final String SRC = "123456";

    public static void main(String[] args) throws Exception {
        System.out.println("\n");
        RsaKeyPair keyPair = generateKeyPair();
        System.out.println("公钥:" + keyPair.getPublicKey());
        System.out.println("私钥:" + keyPair.getPrivateKey());
        System.out.println("\n");
        test1(keyPair);
        System.out.println("\n");
        test2(keyPair);
        System.out.println("\n");
    }

    /**
     * 公钥加密私钥解密
     */
    private static void test1(RsaKeyPair keyPair) throws Exception {
        System.out.println("***************** 公钥加密私钥解密开始 *****************");
        String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC);
        String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1);
        System.out.println("加密前:" + RsaUtils.SRC);
        System.out.println("加密后:" + text1);
        System.out.println("解密后:" + text2);
        if (RsaUtils.SRC.equals(text2)) {
            System.out.println("解密字符串和原始字符串一致,解密成功");
        } else {
            System.out.println("解密字符串和原始字符串不一致,解密失败");
        }
        System.out.println("***************** 公钥加密私钥解密结束 *****************");
    }

    /**
     * 私钥加密公钥解密
     * @throws Exception /
     */
    private static void test2(RsaKeyPair keyPair) throws Exception {
        System.out.println("***************** 私钥加密公钥解密开始 *****************");
        String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC);
        String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1);
        System.out.println("加密前:" + RsaUtils.SRC);
        System.out.println("加密后:" + text1);
        System.out.println("解密后:" + text2);
        if (RsaUtils.SRC.equals(text2)) {
            System.out.println("解密字符串和原始字符串一致,解密成功");
        } else {
            System.out.println("解密字符串和原始字符串不一致,解密失败");
        }
        System.out.println("***************** 私钥加密公钥解密结束 *****************");
    }

    /**
     * 公钥解密
     *
     * @param publicKeyText 公钥
     * @param text 待解密的信息
     * @return /
     * @throws Exception /
     */
    public static String decryptByPublicKey(String publicKeyText, String text) throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text));
        return new String(result);
    }

    /**
     * 私钥加密
     *
     * @param privateKeyText 私钥
     * @param text 待加密的信息
     * @return /
     * @throws Exception /
     */
    public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        byte[] result = doLongerCipherFinal(Cipher.ENCRYPT_MODE, cipher, text.getBytes());
        return Base64.encodeBase64String(result);
    }

    /**
     * 私钥解密
     *
     * @param privateKeyText 私钥
     * @param text 待解密的文本
     * @return /
     * @throws Exception /
     */
    public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text));
        return new String(result);
    }

    /**
     * 公钥加密
     *
     * @param publicKeyText 公钥
     * @param text 待加密的文本
     * @return /
     */
    public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] result = doLongerCipherFinal(Cipher.ENCRYPT_MODE, cipher, text.getBytes());
        return Base64.encodeBase64String(result);
    }

    private static byte[] doLongerCipherFinal(int opMode,Cipher cipher, byte[] source) throws Exception {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        if (opMode == Cipher.DECRYPT_MODE) {
            out.write(cipher.doFinal(source));
        } else {
            int offset = 0;
            int totalSize = source.length;
            while (totalSize - offset > 0) {
                int size = Math.min(cipher.getOutputSize(0) - 11, totalSize - offset);
                out.write(cipher.doFinal(source, offset, size));
                offset += size;
            }
        }
        out.close();
        return out.toByteArray();
    }

    /**
     * 构建RSA密钥对
     *
     * @return /
     * @throws NoSuchAlgorithmException /
     */
    public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
        String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        return new RsaKeyPair(publicKeyString, privateKeyString);
    }


    /**
     * RSA密钥对对象
     */
    public static class RsaKeyPair {

        private final String publicKey;
        private final String privateKey;

        public RsaKeyPair(String publicKey, String privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }

        public String getPublicKey() {
            return publicKey;
        }

        public String getPrivateKey() {
            return privateKey;
        }

    }
}

4. 用户登录controller

 @Log("用户登录")
    @ApiOperation("登录授权")
    @AnonymousPostMapping(value = "/login")
    public ResponseEntity<Object> login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception {
        // 密码解密
        String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword());
        String username = authUser.getUsername();
        String ip = StringUtils.getIp(request);
        String browser = StringUtils.getBrowser(request);
//        String address = StringUtils.getCityInfo(ip);

//        1.验证当前ip是否锁定
        List<SysIpLock> sysIpLock = sysIpLockService.findByIp(ip);
        // 获取当前日期的Date对象
        Date currentDate = new Date();
        if(sysIpLock != null &&  sysIpLock.size() > 0){
//            ip多个信息里找最新的一个锁过期时间判断
            SysIpLock sysIpLockFrist = sysIpLock.get(0);
            if(sysIpLockFrist.getIpLockTime().compareTo(currentDate) > 0){
                throw new BadRequestException("ip已锁定,稍后再试");
            }else{
//              有ip锁记录,但是释放了,依旧要查用户
                List<SysIpLock> sysIpLockList = sysIpLockService.findLockByUserName(username);
                if(sysIpLockList != null &&  sysIpLockList.size() > 0){
//              账号多个信息里找最新的一个锁过期时间判断
                    SysIpLock sysIpLock1 = sysIpLockList.get(0);
                    if(sysIpLock1.getLockDateEnd().compareTo(currentDate) > 0){
                        throw new BadRequestException("账号已锁定,稍后再试");
                    }
                }
            }
        }else{
//        2.验证用户是否锁定
//        2.1先去sys_ip_lock里看用户是否锁定
            List<SysIpLock> sysIpLockList = sysIpLockService.findLockByUserName(username);
            if(sysIpLockList != null &&  sysIpLockList.size() > 0){
//            账号多个信息里找最新的一个锁过期时间判断
                SysIpLock sysIpLockFrist = sysIpLockList.get(0);
                if(sysIpLockFrist.getLockDateEnd().compareTo(currentDate) > 0){
                    throw new BadRequestException("账号已锁定,稍后再试");
                }
            }
        }

        //比较密码
//        根据用户名获取数据库密码---判断用户是否输入正确密码
       String encode = userService.findByUserName(username);
       boolean matches = passwordEncoder.matches(password,encode);
        SysLog sysLog = new SysLog("LOGIN",System.currentTimeMillis());
//        密码正确与否都交给下面框架jwt搞定,这里负责记录登录日志
        sysLogService.saveLog(username, browser, ip, sysLog, matches);
        if(matches){
            // 保存登录信息(redis)
//            loginUserLockService.save(authUser.getUsername(),0,request);
        }else{
            // 保存登录信息(redis)
//        loginUserLockService.save(authUser.getUsername(),1, request);
//            判断log表一段时间内是否超过用户输入密码错误次数,

            Timestamp timestampNow = new Timestamp(System.currentTimeMillis());
            Timestamp timestampNowNoCalendar = new Timestamp(System.currentTimeMillis());
            // 使用Calendar进行时间计算
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(timestampNowNoCalendar);
            calendar.add(Calendar.HOUR, 2); // 在当前时间上加两个小时

            Calendar calendarAgain = Calendar.getInstance();
            calendarAgain.setTime(timestampNowNoCalendar);
            calendarAgain.add(Calendar.HOUR, -2); // 在当前时间上减去两个小时

            // 获取加两个小时后的Timestamp
            Timestamp twoHoursLater = new Timestamp(calendar.getTimeInMillis());
            // 获取加两个小时前的Timestamp
            Timestamp twoHoursBefore = new Timestamp(calendarAgain.getTimeInMillis());

            Integer usernameFailNumber = sysLogService.findFailCountByUsername(username,timestampNow,twoHoursBefore);
            Integer ipFailNumber = sysLogService.findFailCountByIp(ip,timestampNow,twoHoursBefore);
//            超过失败次数就想记录ip和username的sys_ip_lock表加锁记录
            if(usernameFailNumber >= 3){
                SysIpLock sysIpLock1 = new SysIpLock();
                sysIpLock1.setUsername(username);
                sysIpLock1.setLockPwd(true);
                sysIpLock1.setLockType(false);
                sysIpLock1.setLockDateEnd(twoHoursLater);
//                ip这两个字段设置not null
                sysIpLock1.setIp(ip);
                sysIpLock1.setIpStatus(false);
                sysIpLockService.create(sysIpLock1);
//                sysIpLockService.save(sysIpLock1);
            }
            if(ipFailNumber >= 6){
                SysIpLock sysIpLock2 = new SysIpLock();
                sysIpLock2.setIp(ip);
                sysIpLock2.setLockType(true);
                sysIpLock2.setIpStatus(true);
                sysIpLock2.setIpLockTime(twoHoursLater);
//                插入无用的username失败状态
                sysIpLock2.setUsername(username);
                sysIpLock2.setLockPwd(false);
                sysIpLockService.create(sysIpLock2);
//                sysIpLockService.save(sysIpLock2);
            }
        }

        // 查询验证码
        String code = (String) redisUtils.get(authUser.getUuid());
        // 清除验证码
        redisUtils.del(authUser.getUuid());
        if (StringUtils.isBlank(code)) {
            throw new BadRequestException("验证码不存在或已过期");
        }
        if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) {
            throw new BadRequestException("验证码错误");
        }
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(authUser.getUsername(), password);
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 生成令牌与第三方系统获取令牌方式
        // UserDetails userDetails = userDetailsService.loadUserByUsername(userInfo.getUsername());
        // Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        // SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = tokenProvider.createToken(authentication);
        final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();
        // 返回 token 与 用户信息
        Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
            put("token", properties.getTokenStartWith() + token);
            put("user", jwtUserDto);
        }};
        if (loginProperties.isSingleLogin()) {
            // 踢掉之前已经登录的token
            onlineUserService.kickOutForUsername(authUser.getUsername());
        }
        // 保存在线信息
        onlineUserService.save(jwtUserDto, token, request);
        // 返回登录信息
        return ResponseEntity.ok(authInfo);
    }

controller里面关于密码的(接着是ip和用户是否锁定暂时不看)
在这里插入图片描述

在这里插入图片描述

总结

这只是用户登录处理简单处理,重头戏是Security认证流程用户登录:断点看流程认证

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/616143.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HCIP_BGP综合实验

一&#xff1a;实验拓扑&#xff1a; 二&#xff1a;实验要求&#xff1a; 1、AS1中存在两个环回&#xff0c;一个地址为192.168.1.0/24&#xff0c;该地址不能在任何协议中宣告; AS3中存在两个环回一个地址为192.168.2.0/24&#xff0c;该地址不能在任何协议中宣告&am…

JAVA课程设计

一&#xff1a;Java连接mysql数据库 1.1点击进入mysql jar包下载官网 MySQL :: MySQL Community Downloads 将下载好的压缩包进行解压 解压之后下图就是连接数据库所用到的jar包&#xff1a; 将jar包复制到IDEA所用的项目下&#xff0c;放置jar包的目录为lib&#xff0c;需要…

医院如何做好漏费管理?什么是控费系统?控费系统现在成熟吗?

在中国深厚的人情土壤之中&#xff0c;某些医院里的医技科室&#xff0c;宛如隐秘的灰色地带&#xff0c;悄然滋生着利用职务之便谋取私利的暗流。这些科室的医务人员&#xff0c;以低于医院明文规定的收费标准&#xff0c;私下里为熟识的患者提供检查服务&#xff0c;仿佛形成…

IM是什么意思?

IM&#xff08;即时通讯&#xff09;作为现代通讯领域的重要且普遍应用&#xff0c;已成为人们日常生活和工作中不可或缺的通信方式。随着科技的不断发展和互联网的普及&#xff0c;IM工具通过实时信息传递&#xff0c;将沟通变得更加迅速、便捷、高效。 IM的诞生极大地改变了…

探索全画面塑料焊接透光率检测仪的科技魅力

在精密工业和科研领域中&#xff0c;对材料的光学性能有着严格的要求。全画面塑料焊接透光率检测仪是一种先进的设备&#xff0c;它能够精确测量塑料焊接接头的透光率&#xff0c;确保焊接质量符合高标准。本文将详细介绍这一设备的特点、工作原理以及它在实际应用中的重要性。…

未授权访问:JBoss未授权访问漏洞

目录 1、漏洞原理  2、环境搭建 3、未授权访问 4、利用jboss.deployment getshell 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c;还有其他大佬…

ppt转pdf的java实现

一、实现方式 java采用jacob包的功能&#xff0c;把ppt演示文稿转换为pdf。 支持文件格式&#xff1a;pptx,ppt 二、事先准备 1、依赖于office&#xff0c;需安装office办公软件 2、需要下载一个jacob-1.20-x64.dll的文件&#xff0c;放到java的bin目录下。 文件可以网上搜…

【DevOps】Linux 安全:iptables 组成、命令及应用场景详解

导读&#xff1a;全面掌握 iptables&#xff1a;从基础到实践 在 Linux 系统中&#xff0c;iptables 是一个非常强大的工具&#xff0c;它不仅是系统管理员用来构建和管理网络防火墙的首选工具&#xff0c;而且也是一个功能丰富的网络流量处理系统。无论是进行包过滤、监控网络…

二叉树进阶 --- 上

目录 1. 二叉搜索树的概念及结构 1.1. 二叉搜索树的概念 1.2. 二叉搜索树的结构样例 2. 二叉搜索树的实现 2.1. insert 的非递归实现 2.2. find 的非递归实现 2.3. erase 的非递归实现 2.3.1. 第一种情况&#xff1a;所删除的节点的左孩子为空 2.3.1.1. 错误的代码 2…

【工具篇】-什么是.NET

“.NET"&#xff1a;.NET Core是由Microsoft开发&#xff0c;目前在.NET Foundation(一个非营利的开源组织)下进行管理。.NET Core是用C#和C编写的&#xff0c;并采用MIT协议作为开源协议。 简单来说&#xff1a;就是开发框架。 .NET 又称 .NET 平台或 .NET 框架&#xf…

Container exited with a non-zero exit code 1

最近遇到运行yarn pi的时候遇到如下问题。 很明显是container出错了&#xff0c;但是错误没有提示的很清楚。然后去看nodemanager日志也是如此。这时候笔者第一个想到要去看container的执行日志。container具体的日志目录位置是通过YARN的配置文件&#xff08;如yarn-site.xml&…

JavaSE——集合框架一(1/7)-集合体系概述(集合体系结构,Collection集合体系)、Collection的常用方法(介绍,实例演示,代码)

目录 集合体系概述 集合体系结构 Collection集合体系 Collection的常用方法 介绍 实例演示 完整代码 集合体系概述 集合体系结构 集合是一种容器&#xff0c;用来装数据的&#xff0c;类似于数组&#xff0c;但集合的大小可变&#xff0c;开发中也非常常用。 为了满足…

sql注入之bool盲注

目录 盲注步骤 1、进入靶场 2、如下图所示输入&#xff1f;id1‘ 判断此时存在注入点 3、判断列数 ​编辑 4、开始盲注 普通的python脚本 代码思想 结果 二分查找python脚本 二分查找算法思想简介 二分查找与普通查找的主要差距 代码思想 代码 结果​编辑 下面以…

Fcos源码训练编译问题

训练fcos代码时出现问题 ImportError: cannot import name ‘_C’ 原因是没有对代码进行编译 运行python setup.py develop --no-deps进行代码编译 编译过程中出现报错&#xff1a; fcos_core/csrc/cuda/ROIAlign_cuda.cu:5:10: fatal error: THC/THC.h: No such file or dire…

iphone进入恢复模式怎么退出?分享2种退出办法!

iPhone手机莫名其妙的进入到了恢复模式&#xff0c;或者是某些原因需要手机进入恢复模式&#xff0c;但是之后我们不知道如何退出恢复模式怎么办&#xff1f; 通常iPhone进入恢复模式的常见原因主要是软件问题、系统升级失败、误操作问题等导致。那iphone进入恢复模式怎么退出&…

Python-VBA函数之旅-staticmethod函数

目录 一、staticmethod函数的常见应用场景 二、staticmethod函数使用注意事项 三、如何用好staticmethod函数&#xff1f; 1、staticmethod函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://blog…

【EMQX实践】如何感知设备上下线?

序言 在智能物联时代&#xff0c;存设备需要联网上云场景。EMQX在此场景中属于设备连接网关关键节点&#xff0c;EMQX不紧紧只是消息中间件的作用&#xff0c;我们更需要监控哪些设备什么时候连接上线&#xff0c;又在什么时候断开下线。 为什么需要感知设备上下线 感知设备…

二叉树介绍

引入 定义 区别 定义不同 形态不同 基本形态

vscode默认终端设置为cmd的方法

vscode默认终端是powershell,执行某些命令时会提示权限等问题&#xff0c;如果更习惯使用cmd终端的话&#xff0c;可以将默认终端配置为cmd。 方法一&#xff1a; 方法二&#xff1a; 如果你想更改默认的终端&#xff0c;可以通过以下步骤操作&#xff1a; 打开 VSCode。使用…

Applied Spatial Statistics(五)线性回归 I

Applied Spatial Statistics&#xff08;五&#xff09;线性回归 I 该笔记本演示了&#xff1a; 线性回归系数估计在假设下是无偏的如何围绕系数估计构建 bootstrap 置信区间残差图Q-Q图 1. 线性回归系数估计在假设下是无偏的 import numpy as np import matplotlib.pyplot…