Jelajahi Sumber

登录认证添加RSA非对称加密

bihuisong 1 tahun lalu
induk
melakukan
185f8c1321

+ 7 - 1
sooka-api/pom.xml

@@ -18,5 +18,11 @@
     <description>
         sooka-api系统接口
     </description>
-
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.0</version>
+        </dependency>
+    </dependencies>
 </project>

+ 32 - 0
sooka-auth/src/main/java/com/sooka/auth/controller/CorsConfiguration.java

@@ -0,0 +1,32 @@
+package com.sooka.auth.controller;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CorsConfiguration implements WebMvcConfigurer {
+    @Bean
+    public WebMvcConfigurer corsConfigurer() {
+        return new WebMvcConfigurer() {
+            @Override
+            public void addCorsMappings(CorsRegistry registry) {
+                registry.addMapping("/**")
+//                        .allowedOrigins("*")  springBoot2.4.0之前版本
+                        .allowedOriginPatterns("*")   //springBoot新版本方法
+                        .allowCredentials(true)
+                        .allowedMethods("GET", "POST", "PUT", "DELETE");
+            }
+        };
+    }
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        // 设置允许跨域的路由
+        registry.addMapping("/**")
+                // 设置允许跨域请求的域名
+                .allowedOriginPatterns("*")
+                // 设置允许的方法
+                .allowedMethods("GET","POST","DELETE","PUT");
+    }
+}

+ 58 - 2
sooka-auth/src/main/java/com/sooka/auth/controller/TokenController.java

@@ -3,9 +3,12 @@ package com.sooka.auth.controller;
 import com.sooka.auth.form.LoginBody;
 import com.sooka.auth.form.RegisterBody;
 import com.sooka.auth.service.SysLoginService;
+import com.sooka.auth.util.RsaUtil;
+import com.sooka.auth.util.SecretKeyBo;
 import com.sooka.common.core.domain.R;
 import com.sooka.common.core.utils.JwtUtils;
 import com.sooka.common.core.utils.StringUtils;
+import com.sooka.common.redis.service.RedisService;
 import com.sooka.common.security.auth.AuthUtil;
 import com.sooka.common.security.service.TokenService;
 import com.sooka.common.security.utils.SecurityUtils;
@@ -16,7 +19,11 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * token 控制
@@ -31,12 +38,61 @@ public class TokenController {
     @Autowired
     private SysLoginService sysLoginService;
 
+    @Resource
+    private RedisService redisService;
+
+    /**
+     * 获取秘钥接口
+     * 前端请求后该方法会生成一对秘钥,分别为公钥和私钥
+     * 将公钥返回给前端用于加密,私钥存入缓存(60s)用于后台解密
+     * Author 李猛
+     * Pc端调用
+     */
+    @PostMapping("getSecretKey")
+    public R<?> getSecretKey(HttpServletRequest request) {
+        String sessionId = request.getSession().getId();
+        return getSecretKey(sessionId);
+    }
+
+
+    /**
+     * 改造获取秘钥接口
+     * App、Pc端通用
+     * Author 李猛
+     */
+    public R<?> getSecretKey(String sessionId) {
+        String publicKey;
+        try {
+            SecretKeyBo bo = RsaUtil.genKeyPair();
+            redisService.setCacheObject(sessionId, bo.getPrivateKey(), 60L, TimeUnit.SECONDS);
+            publicKey = bo.getPublicKey();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+        if (StringUtils.isNotEmpty(publicKey)) {
+            return R.ok(publicKey, "操作成功");
+        }
+        return R.fail("数据异常,请稍后重试");
+    }
+
     @PostMapping("login")
-    public R<?> login(@RequestBody LoginBody form) {
+    public R<?> login(@RequestBody LoginBody form, HttpServletRequest request) {
+        //解密密码字符串
+        sysLoginService.decryptPassword(form, request);
+        // 用户登录
+//        LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword());
+        // 获取登录token
+        return R.ok(login(form));
+    }
+
+    public Map login(LoginBody form) {
         // 用户登录
         LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword());
         // 获取登录token
-        return R.ok(tokenService.createToken(userInfo));
+        Map map = tokenService.createToken(userInfo);
+        LoginUser user = tokenService.getLoginUser(map.get("access_token").toString());
+        map.put("userinfo", user);
+        return map;
     }
 
     @DeleteMapping("logout")

+ 34 - 0
sooka-auth/src/main/java/com/sooka/auth/service/SysLoginService.java

@@ -1,5 +1,7 @@
 package com.sooka.auth.service;
 
+import com.sooka.auth.form.LoginBody;
+import com.sooka.auth.util.RsaUtil;
 import com.sooka.common.core.constant.CacheConstants;
 import com.sooka.common.core.constant.Constants;
 import com.sooka.common.core.constant.SecurityConstants;
@@ -18,6 +20,8 @@ import com.sooka.system.api.model.LoginUser;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * 登录校验方法
  *
@@ -124,4 +128,34 @@ public class SysLoginService {
         }
         recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功");
     }
+
+
+    /**
+     * Pc根据sessionId获取缓存中对应的私钥进行解密,将解密后的密码替换form对象中原有的密码加密字符串
+     * Author 李猛
+     * */
+    public void decryptPassword(LoginBody form, HttpServletRequest request){
+        String sessionId = request.getSession().getId();
+        decryptPassword(form, sessionId);
+//        String privateKey = redisService.getCacheObject(sessionId);
+//        try {
+//            form.setPassword(RsaUtil.decrypt(form.getPassword(),privateKey));
+//        } catch (Exception e) {
+//            throw new RuntimeException(e);
+//        }
+    }
+
+    /**
+     * 根据sessionId获取缓存中对应的私钥进行解密,将解密后的密码替换form对象中原有的密码加密字符串
+     * Author 李猛
+     * */
+    public void decryptPassword(LoginBody form, String sessionId){
+//        String sessionId = request.getSession().getId();
+        String privateKey = redisService.getCacheObject(sessionId);
+        try {
+            form.setPassword(RsaUtil.decrypt(form.getPassword(),privateKey));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
 }

+ 106 - 0
sooka-auth/src/main/java/com/sooka/auth/util/RsaUtil.java

@@ -0,0 +1,106 @@
+package com.sooka.auth.util;
+
+import javax.crypto.Cipher;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+/**
+ * 1.后端使用RSA算法生成一套密钥
+ * 2.前端使用接口获取后端公钥
+ * 3.后端将公钥传给前端,私钥留在本地服务器
+ * 4.前端使用公钥对明文加密,传输到后端
+ * 5.后端使用私钥解密,将密文转为明文
+ * Author 李猛
+ */
+public class RsaUtil {
+
+    /**
+     * 密钥长度 于原文长度对应 以及越长速度越慢
+     */
+    private final static int KEY_SIZE = 512;
+
+    /**
+     * 随机生成的一套密钥对
+     */
+    public static SecretKeyBo genKeyPair() throws NoSuchAlgorithmException {
+        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
+        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
+        // 初始化密钥对生成器
+        keyPairGen.initialize(KEY_SIZE, new SecureRandom());
+        // 生成一个密钥对,保存在keyPair中
+        KeyPair keyPair = keyPairGen.generateKeyPair();
+        // 得到私钥
+        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+        // 得到公钥
+        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+        String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
+        // 得到私钥字符串
+        String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
+
+        return new SecretKeyBo()
+                .setPrivateKey(privateKeyString)
+                .setPublicKey(publicKeyString);
+    }
+
+    /**
+     * RSA公钥加密
+     *
+     * @param str    加密字符串
+     * @param publicKey 公钥
+     * @return 密文
+     * @throws Exception 加密过程中的异常信息
+     */
+    public static String encrypt(String str, String publicKey) throws Exception {
+        //base64编码的公钥
+        byte[] decoded = Base64.getDecoder().decode(publicKey);
+        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
+        //RSA加密
+        Cipher cipher = Cipher.getInstance("RSA");
+        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
+        return Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
+    }
+
+    /**
+     * RSA私钥解密
+     *
+     * @param str    加密字符串
+     * @param privateKey 私钥
+     * @return 明文字符串
+     * @throws Exception 解密过程中的异常信息
+     */
+    public static String decrypt(String str, String privateKey) throws Exception {
+        //64位解码加密后的字符串
+        byte[] inputByte = Base64.getDecoder().decode(str);
+        //base64编码的私钥
+        byte[] decoded = Base64.getDecoder().decode(privateKey);
+        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
+        //RSA解密
+        Cipher cipher = Cipher.getInstance("RSA");
+        cipher.init(Cipher.DECRYPT_MODE, priKey);
+        return new String(cipher.doFinal(inputByte));
+    }
+
+    public static void main(String[] args) throws Exception {
+        SecretKeyBo bo = RsaUtil.genKeyPair();
+        //公钥
+        System.out.println(bo.getPublicKey());
+        //私钥
+        System.out.println(bo.getPrivateKey());
+        //加密
+        String str1 = RsaUtil.encrypt("123",bo.getPublicKey());
+        System.out.println(str1);
+        //解密
+        String str2 = RsaUtil.decrypt(str1,bo.getPrivateKey());
+        System.out.println(str2);
+    }
+
+}
+
+
+
+

+ 17 - 0
sooka-auth/src/main/java/com/sooka/auth/util/SecretKeyBo.java

@@ -0,0 +1,17 @@
+package com.sooka.auth.util;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * RSA随机秘钥实体类
+ * Author 李猛
+ * */
+@Data
+@Accessors(chain = true)
+public class SecretKeyBo {
+    private String publicKey;
+    private String privateKey;
+}
+
+