单体项目登录成功;全局异常待处理;基本可用
This commit is contained in:
parent
2ab12ec2a7
commit
5193598bb4
|
|
@ -15,7 +15,7 @@ import com.ruoyi.system.api.factory.RemoteFileFallbackFactory;
|
|||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@FeignClient(contextId = "remoteFileService", value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class)
|
||||
@FeignClient(contextId = "remoteFileService",url = "${feign.debug.url.file:}", value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class)
|
||||
public interface RemoteFileService
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import com.ruoyi.system.api.factory.RemoteLogFallbackFactory;
|
|||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@FeignClient(contextId = "remoteLogService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteLogFallbackFactory.class)
|
||||
@FeignClient(contextId = "remoteLogService",url = "${feign.debug.url.system:}", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteLogFallbackFactory.class)
|
||||
public interface RemoteLogService
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import com.ruoyi.system.api.model.LoginUser;
|
|||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class)
|
||||
@FeignClient(contextId = "remoteUserService",url = "${feign.debug.url.system:}", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class)
|
||||
public interface RemoteUserService
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -48,13 +48,11 @@
|
|||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ruoyi-gateway -->
|
||||
<!--验证码 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-gateway</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
<groupId>pro.fessional</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package com.ruoyi.web.admin.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
||||
import com.google.code.kaptcha.util.Config;
|
||||
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_BORDER;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_BORDER_COLOR;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_IMAGE_HEIGHT;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_IMAGE_WIDTH;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_NOISE_COLOR;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_NOISE_IMPL;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_OBSCURIFICATOR_IMPL;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_CONFIG_KEY;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_IMPL;
|
||||
|
||||
/**
|
||||
* 验证码配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
public class CaptchaConfig
|
||||
{
|
||||
@Bean(name = "captchaProducer")
|
||||
public DefaultKaptcha getKaptchaBean()
|
||||
{
|
||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||
Properties properties = new Properties();
|
||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||
properties.setProperty(KAPTCHA_BORDER, "yes");
|
||||
// 验证码文本字符颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
|
||||
// 验证码图片宽度 默认为200
|
||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
||||
// 验证码图片高度 默认为50
|
||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
||||
// 验证码文本字符大小 默认为40
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
|
||||
// KAPTCHA_SESSION_KEY
|
||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
|
||||
// 验证码文本字符长度 默认为5
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
|
||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
||||
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
||||
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
||||
Config config = new Config(properties);
|
||||
defaultKaptcha.setConfig(config);
|
||||
return defaultKaptcha;
|
||||
}
|
||||
|
||||
@Bean(name = "captchaProducerMath")
|
||||
public DefaultKaptcha getKaptchaBeanMath()
|
||||
{
|
||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||
Properties properties = new Properties();
|
||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||
properties.setProperty(KAPTCHA_BORDER, "yes");
|
||||
// 边框颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
|
||||
// 验证码文本字符颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
|
||||
// 验证码图片宽度 默认为200
|
||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
||||
// 验证码图片高度 默认为50
|
||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
||||
// 验证码文本字符大小 默认为40
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
|
||||
// KAPTCHA_SESSION_KEY
|
||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
|
||||
// 验证码文本生成器
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.web.admin.config.KaptchaTextCreator");
|
||||
// 验证码文本字符间距 默认为2
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
|
||||
// 验证码文本字符长度 默认为5
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
|
||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
||||
// 验证码噪点颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
|
||||
// 干扰实现类
|
||||
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
|
||||
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
||||
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
||||
Config config = new Config(properties);
|
||||
defaultKaptcha.setConfig(config);
|
||||
return defaultKaptcha;
|
||||
}
|
||||
}
|
||||
|
|
@ -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,45 @@
|
|||
package com.ruoyi.web.admin.config.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 验证码配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "security.captcha")
|
||||
public class CaptchaProperties
|
||||
{
|
||||
/**
|
||||
* 验证码开关
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 验证码类型(math 数组计算 char 字符)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
public Boolean getEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
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;
|
||||
|
||||
/**
|
||||
* 放行白名单配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "security.ignore")
|
||||
public class IgnoreWhiteProperties
|
||||
{
|
||||
/**
|
||||
* 放行白名单配置,网关不校验此处的白名单
|
||||
*/
|
||||
private List<String> whites = new ArrayList<>();
|
||||
|
||||
public List<String> getWhites()
|
||||
{
|
||||
return whites;
|
||||
}
|
||||
|
||||
public void setWhites(List<String> whites)
|
||||
{
|
||||
this.whites = whites;
|
||||
}
|
||||
}
|
||||
|
|
@ -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,152 @@
|
|||
package com.ruoyi.web.admin.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.constant.TokenConstants;
|
||||
import com.ruoyi.common.core.context.SecurityContextHolder;
|
||||
import com.ruoyi.common.core.exception.InnerAuthException;
|
||||
import com.ruoyi.common.core.exception.ServiceException;
|
||||
import com.ruoyi.common.core.utils.JwtUtils;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.redis.service.RedisService;
|
||||
import com.ruoyi.common.security.auth.AuthUtil;
|
||||
import com.ruoyi.common.security.service.TokenService;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
import com.ruoyi.web.admin.config.CustomHttpServletRequest;
|
||||
import com.ruoyi.web.admin.config.properties.IgnoreWhiteProperties;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
|
||||
/**
|
||||
* token过滤器 验证token有效性
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
@Order(-200)
|
||||
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);
|
||||
|
||||
// 排除过滤的 uri 地址,nacos自行添加
|
||||
@Autowired
|
||||
private IgnoreWhiteProperties ignoreWhite;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
String source = request.getHeader(SecurityConstants.FROM_SOURCE);
|
||||
// 内部请求验证 不拦截
|
||||
if (StringUtils.equals(SecurityConstants.INNER, source)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
String requestURI = request.getRequestURI();
|
||||
// 跳过不需要验证的路径
|
||||
if (!StringUtils.matches(requestURI, ignoreWhite.getWhites())) {
|
||||
|
||||
String token = getToken(request);
|
||||
if (StringUtils.isEmpty(token)) {
|
||||
throw new ServiceException("令牌不能为空");
|
||||
|
||||
}
|
||||
Claims claims = JwtUtils.parseToken(token);
|
||||
if (claims == null) {
|
||||
throw new ServiceException("令牌已过期或验证不正确");
|
||||
|
||||
}
|
||||
String userkey = JwtUtils.getUserKey(claims);
|
||||
boolean islogin = redisService.hasKey(getTokenKey(userkey));
|
||||
if (!islogin) {
|
||||
throw new ServiceException("登录状态已过期");
|
||||
|
||||
}
|
||||
String userid = JwtUtils.getUserId(claims);
|
||||
String username = JwtUtils.getUserName(claims);
|
||||
if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) {
|
||||
throw new ServiceException("令牌验证失败");
|
||||
|
||||
}
|
||||
|
||||
SecurityContextHolder.setUserId(userid);
|
||||
SecurityContextHolder.setUserName(username);
|
||||
SecurityContextHolder.setUserKey(userkey);
|
||||
|
||||
CustomHttpServletRequest customHttpServletRequest = new CustomHttpServletRequest(request);
|
||||
// 设置用户信息到请求
|
||||
addHeader(customHttpServletRequest, SecurityConstants.USER_KEY, userkey);
|
||||
addHeader(customHttpServletRequest, SecurityConstants.DETAILS_USER_ID, userid);
|
||||
addHeader(customHttpServletRequest, SecurityConstants.DETAILS_USERNAME, username);
|
||||
//转换为自定义的request
|
||||
request = customHttpServletRequest;
|
||||
|
||||
if (StringUtils.isNotEmpty(token)) {
|
||||
LoginUser loginUser = AuthUtil.getLoginUser(token);
|
||||
if (StringUtils.isNotNull(loginUser)) {
|
||||
AuthUtil.verifyLoginUserExpire(loginUser);
|
||||
SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存key
|
||||
*/
|
||||
private String getTokenKey(String token) {
|
||||
return CacheConstants.LOGIN_TOKEN_KEY + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求token
|
||||
*/
|
||||
private String getToken(HttpServletRequest request) {
|
||||
String token = request.getHeader(TokenConstants.AUTHENTICATION);
|
||||
// 如果前端设置了令牌前缀,则裁剪掉前缀
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
|
||||
token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
private void addHeader(CustomHttpServletRequest customHttpServletRequest, String name, Object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
String valueStr = value.toString();
|
||||
String valueEncode = ServletUtils.urlEncode(valueStr);
|
||||
customHttpServletRequest.addHeader(name, valueEncode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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("验证码错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -151,20 +151,11 @@ mybatis:
|
|||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 加载全局的配置文件
|
||||
#configLocation: classpath:mybatis/mybatis-config.xml
|
||||
|
||||
# PageHelper分页插件
|
||||
pagehelper:
|
||||
helperDialect: mysql
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
# Swagger配置
|
||||
swagger:
|
||||
# 是否开启swagger
|
||||
enabled: true
|
||||
# 请求前缀
|
||||
pathMapping: /dev-api
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
|
|
@ -173,8 +164,54 @@ xss:
|
|||
excludes: /system/notice
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
|
||||
|
||||
##################### 文件模块 ###########################################
|
||||
# 本地文件上传
|
||||
file:
|
||||
domain: http://127.0.0.1:9300
|
||||
path: ruoyi/uploadPath
|
||||
prefix: /statics
|
||||
# FastDFS配置
|
||||
fdfs:
|
||||
domain: http://8.129.231.12
|
||||
soTimeout: 3000
|
||||
connectTimeout: 2000
|
||||
trackerList: 8.129.231.12:22122
|
||||
# Minio配置
|
||||
minio:
|
||||
url: http://8.129.231.12:9000
|
||||
accessKey: minioadmin
|
||||
secretKey: minioadmin
|
||||
bucketName: test
|
||||
######################## 文件模块 ########################################
|
||||
# feign 配置
|
||||
feign:
|
||||
sentinel:
|
||||
enabled: true
|
||||
okhttp:
|
||||
enabled: true
|
||||
httpclient:
|
||||
enabled: false
|
||||
client:
|
||||
config:
|
||||
default:
|
||||
connectTimeout: 10000
|
||||
readTimeout: 10000
|
||||
compression:
|
||||
request:
|
||||
enabled: true
|
||||
response:
|
||||
enabled: true
|
||||
# 设置feign本地调用地址
|
||||
debug:
|
||||
url:
|
||||
system: http://localhost:${server.port}/system
|
||||
file: http://localhost:${server.port}/file
|
||||
# 暴露监控端点
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: '*'
|
||||
# 安全配置
|
||||
security:
|
||||
# 验证码
|
||||
|
|
@ -194,26 +231,13 @@ security:
|
|||
- /auth/register
|
||||
- /*/v2/api-docs
|
||||
- /csrf
|
||||
|
||||
##################### 文件模块 ###########################################
|
||||
# 本地文件上传
|
||||
file:
|
||||
domain: http://127.0.0.1:9300
|
||||
path: ruoyi/uploadPath
|
||||
prefix: /statics
|
||||
|
||||
# FastDFS配置
|
||||
fdfs:
|
||||
domain: http://8.129.231.12
|
||||
soTimeout: 3000
|
||||
connectTimeout: 2000
|
||||
trackerList: 8.129.231.12:22122
|
||||
|
||||
# Minio配置
|
||||
minio:
|
||||
url: http://8.129.231.12:9000
|
||||
accessKey: minioadmin
|
||||
secretKey: minioadmin
|
||||
bucketName: test
|
||||
|
||||
######################## 文件模块 ########################################
|
||||
- /code
|
||||
# Swagger配置
|
||||
swagger:
|
||||
# 是否开启swagger
|
||||
enabled: true
|
||||
# 请求前缀
|
||||
pathMapping: /dev-api
|
||||
title: 系统模块接口文档
|
||||
license: Powered By ruoyi
|
||||
licenseUrl: https://ruoyi.vip
|
||||
|
|
|
|||
|
|
@ -23,57 +23,12 @@ spring:
|
|||
locator:
|
||||
lowerCaseServiceId: true
|
||||
enabled: true
|
||||
discovery:
|
||||
client:
|
||||
simple:
|
||||
instances:
|
||||
ruoyi-file:
|
||||
- uri: http://localhost:8080
|
||||
ruoyi-system:
|
||||
- uri: http://localhost:9090
|
||||
|
||||
# feign 配置
|
||||
feign:
|
||||
sentinel:
|
||||
enabled: true
|
||||
okhttp:
|
||||
enabled: true
|
||||
httpclient:
|
||||
enabled: false
|
||||
client:
|
||||
config:
|
||||
default:
|
||||
connectTimeout: 10000
|
||||
readTimeout: 10000
|
||||
compression:
|
||||
request:
|
||||
enabled: true
|
||||
response:
|
||||
enabled: true
|
||||
|
||||
# 暴露监控端点
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: '*'
|
||||
|
||||
|
||||
|
||||
# 安全配置
|
||||
security:
|
||||
# 验证码
|
||||
captcha:
|
||||
enabled: true
|
||||
type: math
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
enabled: true
|
||||
excludeUrls:
|
||||
- /system/notice
|
||||
# 不校验白名单
|
||||
ignore:
|
||||
whites:
|
||||
- /auth/logout
|
||||
- /auth/login
|
||||
- /auth/register
|
||||
- /*/v2/api-docs
|
||||
- /csrf
|
||||
|
||||
# swagger配置
|
||||
swagger:
|
||||
title: 系统模块接口文档
|
||||
license: Powered By ruoyi
|
||||
licenseUrl: https://ruoyi.vip
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
<!-- 日志存放路径 -->
|
||||
<property name="log.path" value="logs/ruoyi-web-admin" />
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
|
|
|
|||
Loading…
Reference in New Issue