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

前置知识:

前端登录加密看用户登录

PasswordEncoder加密看PasswordEncoder详解

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

1.后端配置rsa私钥

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

2. 读取配置文件

java 复制代码
/*
 *  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 工具类

java 复制代码
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

java 复制代码
 @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认证流程用户登录:断点看流程认证

相关推荐
杨充6 分钟前
13.观察者模式设计思想
java·redis·观察者模式
Lizhihao_8 分钟前
JAVA-队列
java·开发语言
喵叔哟17 分钟前
重构代码之移动字段
java·数据库·重构
喵叔哟17 分钟前
重构代码之取消临时字段
java·前端·重构
fa_lsyk20 分钟前
maven环境搭建
java·maven
Daniel 大东39 分钟前
idea 解决缓存损坏问题
java·缓存·intellij-idea
wind瑞1 小时前
IntelliJ IDEA插件开发-代码补全插件入门开发
java·ide·intellij-idea
HappyAcmen1 小时前
IDEA部署AI代写插件
java·人工智能·intellij-idea
马剑威(威哥爱编程)1 小时前
读写锁分离设计模式详解
java·设计模式·java-ee
鸽鸽程序猿1 小时前
【算法】【优选算法】前缀和(上)
java·算法·前缀和