Merge remote-tracking branch 'origin/master'

This commit is contained in:
zer0Black
2021-04-16 16:48:08 +08:00
10 changed files with 254 additions and 37 deletions
@@ -1,5 +1,7 @@
package com.jero.common.util;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import lombok.extern.slf4j.Slf4j;
import com.jero.common.constant.CommonConstant;
import com.jero.common.constant.DataBaseConstant;
@@ -10,14 +12,16 @@ import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.sql.DataSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -219,6 +223,17 @@ public class CommonUtils {
boolean isExists = fileNameList.stream().anyMatch(name -> fileName.substring(0,fileName.lastIndexOf('.')).contains(name)||fileName.substring(fileName.lastIndexOf('.')).equals(name));
return isExists;
}
/**
* RSA 使用私钥解密
* @date 2021/4/15 16:11
* @param str 待解密的字符串
* @param RSAPrivateKey 私钥
* @return String 解密后的字符串
*/
public static String decryptBtRsaPriKey(String str,String RSAPrivateKey) throws Exception {
RSA rsa = new RSA(RSAPrivateKey, null);
byte[] decrypt = rsa.decrypt(str, KeyType.PrivateKey);
return new String(decrypt);
}
}
@@ -0,0 +1,164 @@
package com.jero.config;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jero.common.api.vo.Result;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* 描述:跨站过滤器
*
* @Author: 马志朝
* @Date: 2021/4/16 14:09
*/
@Component
public class CsrfFilter implements Filter {
/**
* LOGGER
*/
private static final Log LOGGER = LogFactory.getLog(CsrfFilter.class);
/**
* 白名单
*/
private List<String> whiteUrls = new ArrayList<>();
/**
* size
*/
private int size = 0;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
File file = ResourceUtils.getFile("classpath:whiteUrls.txt");
fis = new FileInputStream(file);
isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
String url = null;
while((url = br.readLine()) != null){
whiteUrls.add(url);
}
size = whiteUrls.size();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(isr!=null){
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
try {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 获取请求url地址
String url = req.getRequestURL().toString();
// 获取来源
String referurl = req.getHeader("Referer");
if(isWhiteReq(referurl)){
chain.doFilter(request, response);
}else{
String log = "";
String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String ip = getIp(req);
log = "跨站请求---->>>" + ip + "||" + date + "||" + referurl + "||" + url;
LOGGER.warn(log);
//发送错误信息
JSONObject json = JSONUtil.parseObj(Result.error("监测到跨站请求,请求失败"), false);
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json; charset=utf-8");
PrintWriter out = res.getWriter();
out.append(json.toStringPretty());
}
} catch (Exception e) {
LOGGER.error("doFilter", e);
}
}
/**
* 判断是否是白名单
*/
private boolean isWhiteReq(String referUrl) {
if (referUrl == null || "".equals(referUrl) || size == 0) {
return true;
} else {
String refHost = "";
referUrl = referUrl.toLowerCase();
if (referUrl.startsWith("http://")) {
refHost = referUrl.substring(7);
} else if (referUrl.startsWith("https://")) {
refHost = referUrl.substring(8);
}
for (String urlTemp : whiteUrls) {
if (refHost.contains(urlTemp.toLowerCase())) {
return true;
}
}
}
return false;
}
/**
* 获取登录用户IP地址
* @param request
* @return
*/
public String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.equals("0:0:0:0:0:0:0:1")) {
ip = "localhost";
}
return ip;
}
@Override
public void destroy() {
}
}
@@ -73,6 +73,7 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/sys/cas/client/validateLogin", "anon"); //cas验证登录
filterChainDefinitionMap.put("/sys/randomImage/**", "anon"); //登录验证码接口排除
filterChainDefinitionMap.put("/sys/checkCaptcha", "anon"); //登录验证码接口排除
filterChainDefinitionMap.put("/sys/getRSAPublicKey", "anon"); //获取RSA公钥接口排除
filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除
filterChainDefinitionMap.put("/sys/mLogin", "anon"); //登录接口排除
filterChainDefinitionMap.put("/sys/logout", "anon"); //登出接口排除
@@ -1,7 +1,7 @@
package com.jero.modules.system.controller;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -33,7 +33,9 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.*;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.*;
/**
@@ -71,11 +73,12 @@ public class LoginController {
Result<JSONObject> result = new Result<JSONObject>();
String username = sysLoginModel.getUsername();
String password = sysLoginModel.getPassword();
String rsaPublicKey = sysLoginModel.getRsaPublicKey();
String rsaPrivateKey = String.valueOf(redisUtil.get(rsaPublicKey));
//update-begin--Author:scott Date:20190805 for:暂时注释掉密码加密逻辑,有点问题
//前端密码加密,后端进行密码解密
//password = AesEncryptUtil.desEncrypt(sysLoginModel.getPassword().replaceAll("%2B", "\\+")).trim();//密码解密
//update-begin--Author:scott Date:20190805 for:暂时注释掉密码加密逻辑,有点问题
//update-begin-author:taoyan date:20190828 for:校验验证码
String captcha = sysLoginModel.getCaptcha();
if(captcha==null){
@@ -90,8 +93,13 @@ public class LoginController {
result.error500("验证码错误");
return result;
}
//update-end-author:taoyan date:20190828 for:校验验证码
try {
//解密获取密码和用户名
password = CommonUtils.decryptBtRsaPriKey(password, rsaPrivateKey);
username = CommonUtils.decryptBtRsaPriKey(username, rsaPrivateKey);
} catch (Exception e) {
e.printStackTrace();
}
//1. 校验用户是否有效
//update-begin-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug,if条件永远为false
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
@@ -119,7 +127,7 @@ public class LoginController {
// 重试登录次数加一
retryCount++;
if( retryCount == 1){
redisUtil.set(RETRY_LOGIN_PREFIX + username,retryCount, 60 * 30);
redisUtil.set(RETRY_LOGIN_PREFIX + username,retryCount,60 * 30);
}else {
redisUtil.set(RETRY_LOGIN_PREFIX + username,retryCount,redisUtil.getExpire(RETRY_LOGIN_PREFIX + username));
}
@@ -534,24 +542,14 @@ public class LoginController {
* @param
* @return com.jero.common.api.vo.Result<java.lang.String>
*/
@ApiOperation("获取RSA公钥")
@GetMapping("/getRSAPublicKey")
public Result<String> getRSAPublicKey(){
KeyPairGenerator keyPairGenerator = null;
try {
keyPairGenerator = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
assert keyPairGenerator != null;
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 得到私钥
PrivateKey privateKey = keyPair.getPrivate();
// 得到公钥
PublicKey publicKey = keyPair.getPublic();
//base64编码
String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());
String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());
RSA rsa = new RSA();
String privateKeyBase64 = rsa.getPrivateKeyBase64();
String publicKeyBase64 = rsa.getPublicKeyBase64();
//存到redis key为公钥 value为私钥
redisUtil.set(publicKeyBase64, privateKeyBase64, 60 * 60L);
redisUtil.set(publicKeyBase64, privateKeyBase64, 60L);
Result<String> result = new Result<>();
result.setResult(publicKeyBase64);
return result;
@@ -19,8 +19,8 @@ public class SysLoginModel {
private String captcha;
@ApiModelProperty(value = "验证码key")
private String checkKey;
@ApiModelProperty(value ="RSA公钥")
private String RSAPublicKey;
@ApiModelProperty(value = "RSA公钥")
private String rsaPublicKey;
public String getUsername() {
return username;
@@ -54,11 +54,11 @@ public class SysLoginModel {
this.checkKey = checkKey;
}
public String getRSAPublicKey() {
return RSAPublicKey;
public String getRsaPublicKey() {
return rsaPublicKey;
}
public void setRSAPublicKey(String RSAPublicKey) {
this.RSAPublicKey = RSAPublicKey;
public void setRsaPublicKey(String rsaPublicKey) {
this.rsaPublicKey = rsaPublicKey;
}
}
+5
View File
@@ -9570,6 +9570,11 @@
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true
},
"jsencrypt": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsencrypt/-/jsencrypt-3.1.0.tgz",
"integrity": "sha512-A4fIgyPN38G7wwB5t1Vkpi+w7j/nHKdradl/k9/GQqwAsxJqAJ55j3P5rWO3dvjhzOyWKOmK//WwzPO+o6gW0g=="
},
"jsesc": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+1
View File
@@ -24,6 +24,7 @@
"enquire.js": "^2.1.6",
"js-base64": "^3.6.0",
"js-cookie": "^2.2.0",
"jsencrypt": "^3.0.0-rc.1",
"lodash.get": "^4.4.2",
"lodash.pick": "^4.4.0",
"md5": "^2.2.1",
+15
View File
@@ -71,4 +71,19 @@ export function thirdLogin(token,thirdType) {
'Content-Type': 'application/json;charset=UTF-8'
}
})
}
/**
* 获取RSA公钥
* @returns {*}
*/
export function getRSAPublicKey() {
return axios({
url: `/sys/getRSAPublicKey`,
method: 'get',
timeout: 5000,
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
}
+22 -4
View File
@@ -182,6 +182,9 @@
import { ACCESS_TOKEN ,ENCRYPTED_STRING} from "@/store/mutation-types"
import { putAction,postAction,getAction } from '@/api/manage'
import { USER_INFO } from "@/store/mutation-types"
import {getRSAPublicKey} from '@/api/login.js'
const Base64 = require('js-base64').Base64
import {JSEncrypt} from 'jsencrypt'
export default {
components: {},
@@ -211,6 +214,7 @@
currdatetime:'',
randCodeImage:'',
requestCodeSuccess:false,
rsaPublicKey:''
}
},
created () {
@@ -218,6 +222,7 @@
Vue.ls.remove(ACCESS_TOKEN)
this.getRouterData();
this.handleChangeCheckCode();
},
methods: {
...mapActions(['Login', 'Logout', 'PhoneLogin']),
@@ -236,14 +241,19 @@
that.loginBtn = true;
that.form.validateFields([ 'username', 'password','inputCode', 'rememberMe' ], { force: true }, (err, values) => {
if (!err) {
loginParams.username = values.username
loginParams.password = values.password
loginParams.remember_me = values.rememberMe
loginParams.captcha = that.inputCodeContent
loginParams.checkKey = that.currdatetime
// console.log("登录参数",loginParams)
loginParams.rsaPublicKey = that.rsaPublicKey;
// 新建JSEncrypt对象
let encrypt = new JSEncrypt();
encrypt.setPublicKey(loginParams.rsaPublicKey);
// 公钥加密
loginParams.username = encrypt.encrypt(values.username)
loginParams.password = encrypt.encrypt(values.password)
//登录
that.Login(loginParams).then((res) => {
//登录成功
this.loginSuccess()
}).catch((err) => {
if (err.code === 500) {
@@ -309,6 +319,14 @@
}).catch(()=>{
this.requestCodeSuccess=false
})
this.getPublicKey();
},
//获取RSA公钥
getPublicKey(){
// 获取公钥
getRSAPublicKey().then(res => {
this.rsaPublicKey = res.result
})
},
loginSuccess () {
this.$router.push({ path: "/dashboard/analysis" }).catch((res)=>{})