✨ 新增图形验证码,提升系统安全性
This commit is contained in:
@@ -43,6 +43,12 @@
|
||||
<groupId>com.hccake</groupId>
|
||||
<artifactId>ballcat-spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 图形验证码 -->
|
||||
<dependency>
|
||||
<groupId>com.github.anji-plus</groupId>
|
||||
<artifactId>captcha-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.hccake.ballcat.admin;
|
||||
|
||||
import com.anji.captcha.service.CaptchaService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.hccake.ballcat.admin.constants.UrlMappingConst;
|
||||
import com.hccake.ballcat.admin.modules.notify.push.MailNotifyPusher;
|
||||
import com.hccake.ballcat.admin.modules.sys.checker.AdminRuleProperties;
|
||||
import com.hccake.ballcat.admin.oauth.UserInfoCoordinator;
|
||||
import com.hccake.ballcat.admin.oauth.filter.LoginCaptchaFilter;
|
||||
import com.hccake.ballcat.common.mail.MailAutoConfiguration;
|
||||
import com.hccake.ballcat.common.mail.sender.MailSender;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
@@ -10,6 +14,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
@@ -40,4 +45,16 @@ public class UpmsAutoConfiguration {
|
||||
return new MailNotifyPusher(mailSender);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<LoginCaptchaFilter> filterRegistrationBean(ObjectMapper objectMapper,
|
||||
CaptchaService captchaService) {
|
||||
FilterRegistrationBean<LoginCaptchaFilter> bean = new FilterRegistrationBean<>();
|
||||
LoginCaptchaFilter filter = new LoginCaptchaFilter(objectMapper, captchaService);
|
||||
bean.setFilter(filter);
|
||||
// 比密码解密早一步
|
||||
bean.setOrder(-1);
|
||||
bean.addUrlPatterns(UrlMappingConst.OAUTH_LOGIN);
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.hccake.ballcat.admin.oauth;
|
||||
|
||||
import com.anji.captcha.service.CaptchaCacheService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 对于分布式部署的应用,我们建议应用自己实现CaptchaCacheService,比如用Redis,参考service/spring-boot代码示例。
|
||||
* 如果应用是单点的,也没有使用redis,那默认使用内存。 内存缓存只适合单节点部署的应用,否则验证码生产与验证在节点之间信息不同步,导致失败。
|
||||
*
|
||||
* ☆☆☆ SPI: 在resources目录新建META-INF.services文件夹(两层),参考当前服务resources。
|
||||
*
|
||||
* @Title: 使用redis缓存
|
||||
* @author lide1202@hotmail.com
|
||||
* @date 2020-05-12
|
||||
*/
|
||||
public class CaptchaCacheServiceRedisImpl implements CaptchaCacheService {
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "redis";
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Override
|
||||
public void set(String key, String value, long expiresInSeconds) {
|
||||
stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String key) {
|
||||
return stringRedisTemplate.hasKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return stringRedisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.hccake.ballcat.admin.oauth.filter;
|
||||
|
||||
import com.anji.captcha.model.common.ResponseModel;
|
||||
import com.anji.captcha.model.vo.CaptchaVO;
|
||||
import com.anji.captcha.service.CaptchaService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.hccake.ballcat.common.core.result.R;
|
||||
import com.hccake.ballcat.common.core.result.SystemResultCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Hccake 2021/1/11
|
||||
* @version 1.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class LoginCaptchaFilter extends OncePerRequestFilter {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final CaptchaService captchaService;
|
||||
|
||||
private final static String CAPTCHA_VERIFICATION_PARAM = "captchaVerification";
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
String captchaVerification = request.getParameter(CAPTCHA_VERIFICATION_PARAM);
|
||||
|
||||
CaptchaVO captchaVO = new CaptchaVO();
|
||||
captchaVO.setCaptchaVerification(captchaVerification);
|
||||
ResponseModel responseModel = captchaService.verification(captchaVO);
|
||||
|
||||
if (responseModel.isSuccess()) {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
else {
|
||||
// 验证码校验失败,返回信息告诉前端
|
||||
// repCode 0000 无异常,代表成功
|
||||
// repCode 9999 服务器内部异常
|
||||
// repCode 0011 参数不能为空
|
||||
// repCode 6110 验证码已失效,请重新获取
|
||||
// repCode 6111 验证失败
|
||||
// repCode 6112 获取验证码失败,请联系管理员
|
||||
response.setHeader("Content-Type", MediaType.APPLICATION_JSON.toString());
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
response.getWriter().write(
|
||||
objectMapper.writeValueAsString(R.failed(SystemResultCode.UNAUTHORIZED, "Captcha code error")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.hccake.ballcat.admin.oauth.CaptchaCacheServiceRedisImpl
|
||||
@@ -60,6 +60,7 @@
|
||||
<jasypt.version>3.0.3</jasypt.version>
|
||||
<hibernate-validator.version>6.1.7.Final</hibernate-validator.version>
|
||||
<jsoup.version>1.13.1</jsoup.version>
|
||||
<anji-captcha.version>1.2.5</anji-captcha.version>
|
||||
|
||||
<virtual-currency.version>0.2.2</virtual-currency.version>
|
||||
</properties>
|
||||
@@ -353,6 +354,13 @@
|
||||
<artifactId>virtual-currency</artifactId>
|
||||
<version>${virtual-currency.version}</version>
|
||||
</dependency>
|
||||
<!-- 图形验证码 -->
|
||||
<dependency>
|
||||
<groupId>com.github.anji-plus</groupId>
|
||||
<artifactId>captcha-spring-boot-starter</artifactId>
|
||||
<version>${anji-captcha.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@ security:
|
||||
- /bycdao-ui/**
|
||||
- favicon.ico
|
||||
|
||||
# 图形验证码
|
||||
aj:
|
||||
captcha:
|
||||
waterMark: 'BallCat'
|
||||
cacheType: redis
|
||||
|
||||
# 暴露监控端口
|
||||
management:
|
||||
|
||||
Reference in New Issue
Block a user