渗透测试漏洞修复

This commit is contained in:
马三炮 2025-11-25 18:35:29 +08:00
parent 462a4df8af
commit 819512ea6c
5 changed files with 442 additions and 287 deletions

View File

@ -3,8 +3,10 @@ package com.bonus.auth.controller;
import com.bonus.auth.form.LoginBody;
import com.bonus.auth.form.RegisterBody;
import com.bonus.auth.service.SysLoginService;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.exception.CaptchaException;
import com.bonus.common.core.utils.JwtUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.redis.service.RedisService;
@ -46,6 +48,22 @@ public class TokenController
// 用户登录
LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword(),
form.getType(),form.getJwtToken());
if (StringUtils.isEmpty(form.getCode()))
{
throw new CaptchaException("验证码不能为空");
}
if (StringUtils.isEmpty(form.getUuid()))
{
throw new CaptchaException("验证码已失效");
}
String verifyKey = Constants.CAPTCHA_CODE_KEY + form.getUuid();
String captcha = redisService.getCacheObject(verifyKey);
redisService.deleteObject(verifyKey);
if (!form.getCode().equalsIgnoreCase(captcha))
{
throw new CaptchaException("验证码错误");
}
// 获取登录token
return R.ok(tokenService.createToken(userInfo));
}

View File

@ -27,6 +27,13 @@ public class LoginBody
*/
private String jwtToken;
private String code;
/**
* 类型 有值为app登录无需密码
*/
private String uuid;
public String getType() {
return type;
}
@ -65,4 +72,19 @@ public class LoginBody
this.jwtToken = jwtToken;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
}

View File

@ -64,14 +64,7 @@ public class AuthFilter implements GlobalFilter, Ordered
return chain.filter(exchange);
}
String token = getToken(request);
// 获取token中的用户ID
String userId = JwtUtils.getUserId(token);
// 获取用户当前有效的token
String currentToken = redisService.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userId);
// 如果当前token和缓存中的token不一致说明已被挤下线
if (currentToken == null || !currentToken.equals(token)) {
return unauthorizedResponse(exchange,"您的账号已在其他设备登录");
}
if (StringUtils.isEmpty(token) )
{
@ -94,7 +87,14 @@ public class AuthFilter implements GlobalFilter, Ordered
{
return unauthorizedResponse(exchange, "令牌验证失败");
}
// 获取token中的用户ID
String userId = JwtUtils.getUserId(token);
// 获取用户当前有效的token
String currentToken = redisService.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userId);
// 如果当前token和缓存中的token不一致说明已被挤下线
if (currentToken == null || !currentToken.equals(userkey)) {
return unauthorizedResponse(exchange,"您的账号已在其他设备登录");
}
// 设置用户信息到请求
addHeader(mutate, SecurityConstants.USER_KEY, userkey);
addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid);

View File

@ -10,13 +10,24 @@ body {
background-size: 100% 100%;
}
#content{
#content {
width: 19%;
height: 37%;
/*height: 37%;*/
display: flex;
flex-direction: column;
align-content: center;
margin-top: 15.5%;
margin-left: 57%;
}
.title{
.common-box {
height: 42px;
display: flex;
align-items: center;
}
.title {
color: #000;
font-size: 30px;
font-family: "微软雅黑";
@ -24,37 +35,45 @@ body {
letter-spacing: 10px;
text-align: center;
}
.content{
.content {
height: 35%;
margin-top: 13%;
}
.phoneDiv{
height: 35%;
background-color: rgba(255,255,255,0.1);
.phoneDiv, .codeDiv, .pwdDiv {
height: 40px;
background-color: rgba(255, 255, 255, 0.1);
}
.phoneDiv>div{
.phoneDiv > div {
display: inline-block;
}
.phoneDiv>.title{
.phoneDiv > .title {
display: inline-block;
height: 60%;
height: 25px;
width: 25px;
background: url(../img/userName.png) no-repeat;
background-size: 100% 100%;
margin-top: 2%;
margin-left: 2%;
float: left;
/*margin-top: 2%;*/
/*margin-left: 2%;*/
/*float: left;*/
margin-right: 2%;
}
#phoneDiv{
width: 80%;
#phoneDiv {
/*width: 80%;*/
height: 100%;
margin-left: 3%;
float: left;
/*float: left;*/
flex: 1;
}
#username{
#username {
height: 95%;
width: 97%;
background-color: rgba(229,235,241,1);
background-color: rgba(229, 235, 241, 1);
border: 0;
outline: 0;
float: left;
@ -62,55 +81,116 @@ body {
}
.pwdDiv{
height: 35%;
.pwdDiv {
/*height: 35%;*/
height: 40px;
margin-top: 9%;
background-color: rgba(255,255,255,0.1);
background-color: rgba(255, 255, 255, 0.1);
}
.pwdDiv>div{
.pwdDiv > div {
display: inline-block;
}
.pwdDiv>.title{
.pwdDiv > .title {
display: inline-block;
height: 60%;
height: 25px;
width: 25px;
background: url(../img/pwd.png) no-repeat;
background-size: 100% 100%;
margin-top: 2%;
margin-left: 2%;
float: left;
/*margin-top: 2%;*/
/*margin-left: 2%;*/
/*float: left;*/
margin-right: 2%;
}
#pwdDiv{
width: 80%;
#pwdDiv {
/*width: 80%;*/
height: 100%;
margin-left: 3%;
float: left;
/*float: left;*/
flex: 1;
}
#password{
.codeDiv {
/*height: 35%;*/
height: 40px;
margin-top: 9%;
background-color: rgba(255, 255, 255, 0.1);
}
.codeDiv > div {
display: inline-block;
}
.codeDiv > .title {
display: inline-block;
height: 25px;
width: 25px;
background: url(../img/pwd.png) no-repeat;
background-size: 100% 100%;
/*margin-top: 2%;*/
/*margin-left: 2%;*/
/*float: left;*/
margin-right: 2%;
}
#codeDiv {
/*width: 80%;*/
height: 100%;
margin-left: 3%;
/*float: left;*/
flex: 1;
display: flex;
}
#code-img {
height: 40px;
width: 120px;
object-fit: cover;
cursor:pointer;
}
#password {
height: 95%;
width: 97%;
background-color: rgba(229,235,241,1);
background-color: rgba(229, 235, 241, 1);
border: 0;
outline: 0;
float: left;
color: #000;
}
.func{
#code {
height: 95%;
/*width: 97%;*/
background-color: rgba(229, 235, 241, 1);
border: 0;
outline: 0;
/*float: left;*/
color: #000;
flex: 1;
}
.func {
height: 7%;
margin-top: 4%;
display: flex;
}
.func span:last-child{
.func span:last-child {
color: #00367A;
font-size: 13px;
font-family: '微软雅黑';
margin-left: 64%;
cursor: pointer;
}
#login{
#login {
height: 12.5%;
margin-top: 15%;
margin-top: 10%;
background-color: #0857ba;
text-align: center;
line-height: 20px;
@ -120,10 +200,11 @@ body {
line-height: 41px;
cursor: pointer;
}
#login:hover{
background-color: rgba(8,87,186,0.5);
#login:hover {
background-color: rgba(8, 87, 186, 0.5);
}
input::-webkit-input-placeholder{
color: rgba(152,167,191,0.5);
input::-webkit-input-placeholder {
color: rgba(152, 167, 191, 0.5);
}

View File

@ -1,41 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>登录</title>
<link href="css/login.css" type="text/css" rel="stylesheet">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>登录</title>
<link href="css/login.css" type="text/css" rel="stylesheet">
</head>
<body id="allPage">
<div id="content" >
<div class="title">实名制管理系统</div>
<div class="content">
<div class="phoneDiv">
<div class="title"></div>
<div id="phoneDiv">
<input id="username" name="username" type="text" placeholder="手机号"/>
<input id="jwtToken" hidden/>
</div>
</div>
<div class="pwdDiv">
<div class="title"></div>
<div id="pwdDiv">
<input id="password" name="password" type="password" placeholder="密码"/>
</div>
</div>
</div>
<div id="content">
<div class="title">实名制管理系统</div>
<div class="content">
<div class="common-box phoneDiv">
<div class="title"></div>
<div id="phoneDiv">
<input id="username" name="username" type="text" placeholder="手机号"/>
<input id="jwtToken" hidden/>
</div>
</div>
<div class="common-box pwdDiv">
<div class="title"></div>
<div id="pwdDiv">
<input id="password" name="password" type="password" placeholder="密码"/>
</div>
</div>
<div class="common-box codeDiv">
<div class="title"></div>
<div id="codeDiv">
<input id="code" name="code" type="text" placeholder="验证码"/>
<img name="yzm" id="code-img">
</div>
</div>
</div>
<div class="func">
<input id="jzpwd" type="checkbox" /><span style="color: #00367A; font-size: 13px; font-family: '微软雅黑'; ">记住密码</span>
<span onclick="forgetPwd()" style="color: #00367A; font-size: 13px; font-family: '微软雅黑'; ">忘记密码</span>
</div>
<div class="func">
<input id="jzpwd" type="checkbox"/><span
style="color: #00367A; font-size: 13px; font-family: '微软雅黑'; ">记住密码</span>
<span onclick="forgetPwd()" style="color: #00367A; font-size: 13px; font-family: '微软雅黑'; ">忘记密码</span>
</div>
<div onclick="login(this)" id="login">登录</div>
<span id="info" style="color: red"></span>
</div>
<div onclick="login(this)" id="login">登录</div>
<span id="info" style="color: red"></span>
</div>
</body>
<script src="js/libs/jquery-3.6.0.js"></script>
@ -43,225 +51,251 @@
<script src="js/Rsa.js"></script>
<script type="text/javascript" src="./layui/layui.js"></script>
<script type="text/javascript">
layui.use([ 'layer' ], function() {
var layer = layui.layer;
var userName = localStorage.getItem("userName");//用户名
var password = localStorage.getItem("password");//密码
var jzpwd = localStorage.getItem("jzpwd");//是否记住密码
layui.use(['layer'], function () {
var layer = layui.layer;
var userName = localStorage.getItem("userName");//用户名
var password = localStorage.getItem("password");//密码
var jzpwd = localStorage.getItem("jzpwd");//是否记住密码
if(jzpwd != null && jzpwd == "true"){
$("#username").val(userName);
$("#password").val(password);
}
//回车登录,
enterBtn();
if (jzpwd != null && jzpwd == "true") {
$("#username").val(userName);
$("#password").val(password);
}
//回车登录,
enterBtn();
//禁用 F12、鼠标右键
// disabledReviewElement();
});
//禁用 F12、鼠标右键
// disabledReviewElement();
});
if (top != self) {
parent.location.href = '/login.html';
}
var token = localStorage.getItem("smz-token");
if (token != null && token.trim().length != 0) {
$.ajax({
type : 'get',
url : ctxPath + '/users/current?token=' + token,
success : function(data) {
if(data != ''){
location.href = ctxPath + '/index.html';
}
},
error : function(xhr, textStatus, errorThrown) {
var msg = xhr.responseText;
var response = JSON.parse(msg);
var code = response.code;
var message = response.message;
if (code == 401) {
localStorage.removeItem("smz-token");
}
}
});
}
if (top != self) {
parent.location.href = '/login.html';
}
var uuid=null;
var token = localStorage.getItem("smz-token");
if (token != null && token.trim().length != 0) {
$.ajax({
type: 'get',
url: ctxPath + '/users/current?token=' + token,
success: function (data) {
if (data != '') {
location.href = ctxPath + '/index.html';
}
},
error: function (xhr, textStatus, errorThrown) {
var msg = xhr.responseText;
var response = JSON.parse(msg);
var code = response.code;
var message = response.message;
if (code == 401) {
localStorage.removeItem("smz-token");
}
}
});
}
//回车登录,
function enterBtn(){
fastLogin();
function enterBtn() {
fastLogin();
}
function login(obj) {
$(obj).attr("disabled", true);
var username = $.trim($('#username').val());
var password = $.trim($('#password').val());
var jwtToken = $.trim($('#jwtToken').val());
var jzpwd = $("#jzpwd").prop("checked"); // 是否记住密码
if (username == "" || password == "") {
$("#info").html('手机号或者密码不能为空');
$(obj).attr("disabled", false);
} else {
$.ajax({
type : 'post',
contentType : "application/json; charset=utf-8",
url : DATA_URL + '/auth/login',
data : JSON.stringify({
"username" : encryptRsa(username),
"password" : encryptRsa(password),
"jwtToken" : jwtToken
}),
success : function(data) {
if(data.code == '200'){
let roleLevel = data.data.loginUser.sysUser.roleLevel;
console.log(data)
const idNumber = decryptRsa(data.data.loginUser.sysUser.idNumber);
// 4. 解密
const phonenumber = decryptRsa(data.data.loginUser.sysUser.phonenumber);
// if(roleLevel != '5'){
localStorage.setItem("smz-token", data.data.access_token);
//保存用户名密码
localStorage.setItem("userName", username);
localStorage.setItem("password", password);
//保存登录人id
localStorage.setItem("userId", data.data.loginUser.userid);
//保存登录人身份证
localStorage.setItem("userIdNumber", idNumber);
//保存登录人手机号
localStorage.setItem("phonenumber", phonenumber);
//角色等级
localStorage.setItem("roleLevel", roleLevel);
//是否记录密码
localStorage.setItem("jzpwd", jzpwd);
//验证密码强度
var flag = checkPwd(password);
//密码强度过低
if(flag){
//密码强度符合规则
location.href = ctxPath + '/index.html';
}else{
var msg = "您的密码复杂度太低!密码中必须包含【大小字母】、【数字】、【特殊字符】,请您尽快去修改密码。";
layer.alert(msg, { icon: 0 }, function () {
location.href = ctxPath + '/index.html';
});
}
function login(obj) {
$(obj).attr("disabled", true);
var username = $.trim($('#username').val());
var password = $.trim($('#password').val());
var jwtToken = $.trim($('#jwtToken').val());
var code = $.trim($('#code').val());
var jzpwd = $("#jzpwd").prop("checked"); // 是否记住密码
if (username == "" || password == "" || code == "") {
$("#info").html('手机号或者密码或者验证码不能为空');
$(obj).attr("disabled", false);
} else {
$.ajax({
type: 'post',
contentType: "application/json; charset=utf-8",
url: DATA_URL + '/auth/login',
data: JSON.stringify({
"username": encryptRsa(username),
"password": encryptRsa(password),
"jwtToken": jwtToken,
'code': code,
"uuid":uuid
// }else{
// $("#info").html("施工人员级权限无法登录");
// $(obj).attr("disabled", false);
// }
}else{
$("#info").html(data.msg);
$(obj).attr("disabled", false);
}
},
error : function(xhr, textStatus, errorThrown) {
var msg = xhr.responseText;
var response = JSON.parse(msg);
$("#info").html(response.message);
$(obj).attr("disabled", false);
}
});
}),
success: function (data) {
if (data.code == '200') {
}
}
let roleLevel = data.data.loginUser.sysUser.roleLevel;
console.log(data)
const idNumber = decryptRsa(data.data.loginUser.sysUser.idNumber);
// 4. 解密
const phonenumber = decryptRsa(data.data.loginUser.sysUser.phonenumber);
// if(roleLevel != '5'){
localStorage.setItem("smz-token", data.data.access_token);
//保存用户名密码
localStorage.setItem("userName", username);
localStorage.setItem("password", password);
//保存登录人id
localStorage.setItem("userId", data.data.loginUser.userid);
//保存登录人身份证
localStorage.setItem("userIdNumber", idNumber);
//保存登录人手机号
localStorage.setItem("phonenumber", phonenumber);
//角色等级
localStorage.setItem("roleLevel", roleLevel);
//是否记录密码
localStorage.setItem("jzpwd", jzpwd);
//验证密码强度
var flag = checkPwd(password);
//密码强度过低
if (flag) {
//密码强度符合规则
location.href = ctxPath + '/index.html';
} else {
var msg = "您的密码复杂度太低!密码中必须包含【大小字母】、【数字】、【特殊字符】,请您尽快去修改密码。";
layer.alert(msg, {icon: 0}, function () {
location.href = ctxPath + '/index.html';
});
}
//验证密码强度
function checkPwd(password) {
var flag = true;
if (password != null) {
var regex = new RegExp('(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[^a-zA-Z0-9]).{8,20}');
if (!regex.test(password)) {
flag = false;
}
}
return flag;
}
// }else{
// $("#info").html("施工人员级权限无法登录");
// $(obj).attr("disabled", false);
// }
} else {
$("#info").html(data.msg);
$(obj).attr("disabled", false);
getCodeImgFun();
}
},
error: function (xhr, textStatus, errorThrown) {
var msg = xhr.responseText;
var response = JSON.parse(msg);
$("#info").html(response.message);
$(obj).attr("disabled", false);
getCodeImgFun();
}
});
//忘记密码
function forgetPwd(){
location.href = "updPwd.html";
}
}
}
function fastLogin(){
var jwtToken=GetQueryString("token");
console.log(jwtToken);
if(jwtToken==null||jwtToken==undefined){
$(document).keyup(function(event){
if(event.keyCode ==13){
login($("#login"));
}
});
return;
}else{
$("#content").css("display","none");
// layer.open({
// type: 1,
// title: '加载数据提示',
// area: ['70%', '70%'], // 设置宽度和高度
// content: `<div style="width: 100%;height: 100%;text-align: center;display: flex;justify-content: center">正在加载数据中</div>`,
// offset: 'auto', // 将内容居中
// });
layer.msg('自动登录中,请稍后。。。',{
icon:16,
shade: [0.8, '#393D49'],
time:5000
});
}
var url = ctxPath+"/auth/getTokenKey?jwtToken="+jwtToken;
$.ajax({
type : "GET",
contentType: "application/json;charset=UTF-8",
url : url,
success : function(result) {
if(result !== "miss"){
$('#username').val(result);
$('#jwtToken').val(jwtToken);
$('#password').val("edsa12fasf@das");
login();
}else{
console.log("jwtToken解析错误");
}
},
//请求失败,包含具体的错误信息
error : function(e){
console.log(e.status);
console.log(e.responseText);
}
});
}
//验证密码强度
function checkPwd(password) {
var flag = true;
if (password != null) {
var regex = new RegExp('(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[^a-zA-Z0-9]).{8,20}');
if (!regex.test(password)) {
flag = false;
}
}
return flag;
}
function GetQueryString(name){
var reg = new RegExp("(^|&)"+name+"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r!=null)return unescape(r[2]); return null;
}
//忘记密码
function forgetPwd() {
location.href = "updPwd.html";
}
//禁用 F12、鼠标右键
function disabledReviewElement() {
document.onkeydown = function(e) {
if(e.keyCode == 123) {
return false;
}
if(e.ctrlKey && e.shiftKey && e.keyCode == 'I'.charCodeAt(0)) {
return false;
}
if(e.ctrlKey && e.shiftKey && e.keyCode == 'C'.charCodeAt(0)) {
return false;
}
if(e.ctrlKey && e.shiftKey && e.keyCode == 'J'.charCodeAt(0)) {
return false;
}
if(e.ctrlKey && e.keyCode == 'U'.charCodeAt(0)) {
return false;
}
}
document.addEventListener('contextmenu', function (event) {
event.preventDefault()
})
}
function fastLogin() {
var jwtToken = GetQueryString("token");
console.log(jwtToken);
if (jwtToken == null || jwtToken == undefined) {
$(document).keyup(function (event) {
if (event.keyCode == 13) {
login($("#login"));
}
});
return;
} else {
$("#content").css("display", "none");
// layer.open({
// type: 1,
// title: '加载数据提示',
// area: ['70%', '70%'], // 设置宽度和高度
// content: `<div style="width: 100%;height: 100%;text-align: center;display: flex;justify-content: center">正在加载数据中</div>`,
// offset: 'auto', // 将内容居中
// });
layer.msg('自动登录中,请稍后。。。', {
icon: 16,
shade: [0.8, '#393D49'],
time: 5000
});
}
var url = ctxPath + "/auth/getTokenKey?jwtToken=" + jwtToken;
$.ajax({
type: "GET",
contentType: "application/json;charset=UTF-8",
url: url,
success: function (result) {
if (result !== "miss") {
$('#username').val(result);
$('#jwtToken').val(jwtToken);
$('#password').val("edsa12fasf@das");
login();
} else {
console.log("jwtToken解析错误");
}
},
//请求失败,包含具体的错误信息
error: function (e) {
console.log(e.status);
console.log(e.responseText);
}
});
}
function GetQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
//禁用 F12、鼠标右键
function disabledReviewElement() {
document.onkeydown = function (e) {
if (e.keyCode == 123) {
return false;
}
if (e.ctrlKey && e.shiftKey && e.keyCode == 'I'.charCodeAt(0)) {
return false;
}
if (e.ctrlKey && e.shiftKey && e.keyCode == 'C'.charCodeAt(0)) {
return false;
}
if (e.ctrlKey && e.shiftKey && e.keyCode == 'J'.charCodeAt(0)) {
return false;
}
if (e.ctrlKey && e.keyCode == 'U'.charCodeAt(0)) {
return false;
}
}
document.addEventListener('contextmenu', function (event) {
event.preventDefault()
})
}
// 获取图形验证码
function getCodeImgFun() {
$.ajax({
type: 'get',
url: DATA_URL + '/code',
async: false,
success: function (data) {
console.log(data, '获取的验证码')
$('#code-img').attr('src', `data:image/gif;base64,${data.img}`)
uuid = data.uuid;
}
});
}
getCodeImgFun()
$('#code-img').click(() => {
getCodeImgFun()
})
</script>
</html>