parent
2ab12ec2a7
commit
5193598bb4
@ -0,0 +1,58 @@
|
|||||||
|
package com.ruoyi.web.admin.config;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 1763113879@qq.com
|
||||||
|
* @version V2.1
|
||||||
|
* @since 2.1.0 2023/11/16 13:07
|
||||||
|
*/
|
||||||
|
public class CustomHttpServletRequest extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
|
private Map<String,String> headers=new HashMap<>();
|
||||||
|
|
||||||
|
public CustomHttpServletRequest(HttpServletRequest request){
|
||||||
|
super(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addHeader(String name,String value){
|
||||||
|
headers.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeader(String name) {
|
||||||
|
String value=super.getHeader(name);
|
||||||
|
|
||||||
|
if (headers.containsKey(name)){
|
||||||
|
value=headers.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> getHeaderNames() {
|
||||||
|
List<String> names= Collections.list(super.getHeaderNames());
|
||||||
|
names.addAll(headers.keySet());
|
||||||
|
|
||||||
|
return Collections.enumeration(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> getHeaders(String name) {
|
||||||
|
List<String> list= Collections.list(super.getHeaders(name));
|
||||||
|
|
||||||
|
if (headers.containsKey(name)){
|
||||||
|
list.add(headers.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.enumeration(list);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package com.ruoyi.web.admin.config;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码文本生成器
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class KaptchaTextCreator extends DefaultTextCreator
|
||||||
|
{
|
||||||
|
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText()
|
||||||
|
{
|
||||||
|
Integer result = 0;
|
||||||
|
Random random = new Random();
|
||||||
|
int x = random.nextInt(10);
|
||||||
|
int y = random.nextInt(10);
|
||||||
|
StringBuilder suChinese = new StringBuilder();
|
||||||
|
int randomoperands = random.nextInt(3);
|
||||||
|
if (randomoperands == 0)
|
||||||
|
{
|
||||||
|
result = x * y;
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
suChinese.append("*");
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
}
|
||||||
|
else if (randomoperands == 1)
|
||||||
|
{
|
||||||
|
if ((x != 0) && y % x == 0)
|
||||||
|
{
|
||||||
|
result = y / x;
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
suChinese.append("/");
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = x + y;
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
suChinese.append("+");
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (randomoperands == 2)
|
||||||
|
{
|
||||||
|
if (x >= y)
|
||||||
|
{
|
||||||
|
result = x - y;
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
suChinese.append("-");
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = y - x;
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
suChinese.append("-");
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = x + y;
|
||||||
|
suChinese.append(CNUMBERS[x]);
|
||||||
|
suChinese.append("+");
|
||||||
|
suChinese.append(CNUMBERS[y]);
|
||||||
|
}
|
||||||
|
suChinese.append("=?@" + result);
|
||||||
|
return suChinese.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.ruoyi.web.admin.config.properties;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XSS跨站脚本配置
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "security.xss")
|
||||||
|
public class XssProperties
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Xss开关
|
||||||
|
*/
|
||||||
|
private Boolean enabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排除路径
|
||||||
|
*/
|
||||||
|
private List<String> excludeUrls = new ArrayList<>();
|
||||||
|
|
||||||
|
public Boolean getEnabled()
|
||||||
|
{
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(Boolean enabled)
|
||||||
|
{
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getExcludeUrls()
|
||||||
|
{
|
||||||
|
return excludeUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExcludeUrls(List<String> excludeUrls)
|
||||||
|
{
|
||||||
|
this.excludeUrls = excludeUrls;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.ruoyi.web.admin.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||||
|
import com.ruoyi.web.admin.service.ValidateCodeService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码操作处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class CaptchaController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ValidateCodeService validateCodeService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成验证码
|
||||||
|
*/
|
||||||
|
@GetMapping("/code")
|
||||||
|
public AjaxResult getCode(HttpServletResponse response) throws IOException {
|
||||||
|
return validateCodeService.createCaptcha();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.ruoyi.web.admin.service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.exception.CaptchaException;
|
||||||
|
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface ValidateCodeService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 生成验证码
|
||||||
|
*/
|
||||||
|
public AjaxResult createCaptcha() throws IOException, CaptchaException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验验证码
|
||||||
|
*/
|
||||||
|
public void checkCaptcha(String key, String value) throws CaptchaException;
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package com.ruoyi.web.admin.service.impl;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.FastByteArrayOutputStream;
|
||||||
|
|
||||||
|
import com.google.code.kaptcha.Producer;
|
||||||
|
import com.ruoyi.common.core.constant.CacheConstants;
|
||||||
|
import com.ruoyi.common.core.constant.Constants;
|
||||||
|
import com.ruoyi.common.core.exception.CaptchaException;
|
||||||
|
import com.ruoyi.common.core.utils.StringUtils;
|
||||||
|
import com.ruoyi.common.core.utils.sign.Base64;
|
||||||
|
import com.ruoyi.common.core.utils.uuid.IdUtils;
|
||||||
|
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||||
|
import com.ruoyi.common.redis.service.RedisService;
|
||||||
|
import com.ruoyi.web.admin.config.properties.CaptchaProperties;
|
||||||
|
import com.ruoyi.web.admin.service.ValidateCodeService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码实现处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ValidateCodeServiceImpl implements ValidateCodeService
|
||||||
|
{
|
||||||
|
@Resource(name = "captchaProducer")
|
||||||
|
private Producer captchaProducer;
|
||||||
|
|
||||||
|
@Resource(name = "captchaProducerMath")
|
||||||
|
private Producer captchaProducerMath;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisService redisService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CaptchaProperties captchaProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成验证码
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AjaxResult createCaptcha() throws IOException, CaptchaException
|
||||||
|
{
|
||||||
|
AjaxResult ajax = AjaxResult.success();
|
||||||
|
boolean captchaEnabled = captchaProperties.getEnabled();
|
||||||
|
ajax.put("captchaEnabled", captchaEnabled);
|
||||||
|
if (!captchaEnabled)
|
||||||
|
{
|
||||||
|
return ajax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存验证码信息
|
||||||
|
String uuid = IdUtils.simpleUUID();
|
||||||
|
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
|
||||||
|
|
||||||
|
String capStr = null, code = null;
|
||||||
|
BufferedImage image = null;
|
||||||
|
|
||||||
|
String captchaType = captchaProperties.getType();
|
||||||
|
// 生成验证码
|
||||||
|
if ("math".equals(captchaType))
|
||||||
|
{
|
||||||
|
String capText = captchaProducerMath.createText();
|
||||||
|
capStr = capText.substring(0, capText.lastIndexOf("@"));
|
||||||
|
code = capText.substring(capText.lastIndexOf("@") + 1);
|
||||||
|
image = captchaProducerMath.createImage(capStr);
|
||||||
|
}
|
||||||
|
else if ("char".equals(captchaType))
|
||||||
|
{
|
||||||
|
capStr = code = captchaProducer.createText();
|
||||||
|
image = captchaProducer.createImage(capStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||||
|
// 转换流信息写出
|
||||||
|
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ImageIO.write(image, "jpg", os);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
return AjaxResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
ajax.put("uuid", uuid);
|
||||||
|
ajax.put("img", Base64.encode(os.toByteArray()));
|
||||||
|
return ajax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验验证码
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void checkCaptcha(String code, String uuid) throws CaptchaException
|
||||||
|
{
|
||||||
|
if (StringUtils.isEmpty(code))
|
||||||
|
{
|
||||||
|
throw new CaptchaException("验证码不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(uuid))
|
||||||
|
{
|
||||||
|
throw new CaptchaException("验证码已失效");
|
||||||
|
}
|
||||||
|
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
|
||||||
|
String captcha = redisService.getCacheObject(verifyKey);
|
||||||
|
redisService.deleteObject(verifyKey);
|
||||||
|
|
||||||
|
if (!code.equalsIgnoreCase(captcha))
|
||||||
|
{
|
||||||
|
throw new CaptchaException("验证码错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue