代码提交:3-13
This commit is contained in:
@@ -5,11 +5,12 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.ibatis.io.VFS;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -22,6 +23,8 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -30,82 +33,63 @@ import com.ruoyi.common.utils.StringUtils;
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
public class MyBatisConfig
|
||||
{
|
||||
public class MyBatisConfig {
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
|
||||
|
||||
public static String setTypeAliasesPackage(String typeAliasesPackage)
|
||||
{
|
||||
public static String setTypeAliasesPackage(String typeAliasesPackage) {
|
||||
ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
|
||||
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
|
||||
List<String> allResult = new ArrayList<String>();
|
||||
try
|
||||
{
|
||||
for (String aliasesPackage : typeAliasesPackage.split(","))
|
||||
{
|
||||
try {
|
||||
for (String aliasesPackage : typeAliasesPackage.split(",")) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
|
||||
+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
|
||||
+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/"
|
||||
+ DEFAULT_RESOURCE_PATTERN;
|
||||
Resource[] resources = resolver.getResources(aliasesPackage);
|
||||
if (resources != null && resources.length > 0)
|
||||
{
|
||||
if (resources != null && resources.length > 0) {
|
||||
MetadataReader metadataReader = null;
|
||||
for (Resource resource : resources)
|
||||
{
|
||||
if (resource.isReadable())
|
||||
{
|
||||
for (Resource resource : resources) {
|
||||
if (resource.isReadable()) {
|
||||
metadataReader = metadataReaderFactory.getMetadataReader(resource);
|
||||
try
|
||||
{
|
||||
result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
try {
|
||||
result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage()
|
||||
.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.size() > 0)
|
||||
{
|
||||
if (result.size() > 0) {
|
||||
HashSet<String> hashResult = new HashSet<String>(result);
|
||||
allResult.addAll(hashResult);
|
||||
}
|
||||
}
|
||||
if (allResult.size() > 0)
|
||||
{
|
||||
if (allResult.size() > 0) {
|
||||
typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return typeAliasesPackage;
|
||||
}
|
||||
|
||||
public Resource[] resolveMapperLocations(String[] mapperLocations)
|
||||
{
|
||||
public Resource[] resolveMapperLocations(String[] mapperLocations) {
|
||||
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
|
||||
List<Resource> resources = new ArrayList<Resource>();
|
||||
if (mapperLocations != null)
|
||||
{
|
||||
for (String mapperLocation : mapperLocations)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mapperLocations != null) {
|
||||
for (String mapperLocation : mapperLocations) {
|
||||
try {
|
||||
Resource[] mappers = resourceResolver.getResources(mapperLocation);
|
||||
resources.addAll(Arrays.asList(mappers));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
@@ -114,8 +98,7 @@ public class MyBatisConfig
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
|
||||
{
|
||||
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
|
||||
String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
|
||||
String mapperLocations = env.getProperty("mybatis.mapperLocations");
|
||||
String configLocation = env.getProperty("mybatis.configLocation");
|
||||
|
||||
@@ -110,8 +110,8 @@ public class SecurityConfig
|
||||
// 注解标记允许匿名访问的url
|
||||
.authorizeHttpRequests((requests) -> {
|
||||
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
|
||||
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
|
||||
requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
|
||||
// 对于登录login 注册register 验证码captchaImage CAS登录 允许匿名访问
|
||||
requests.antMatchers("/login", "/register", "/captchaImage", "/cas/login").permitAll()
|
||||
// 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
|
||||
/**
|
||||
* 异步任务管理器
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class AsyncManager
|
||||
@@ -21,7 +21,7 @@ public class AsyncManager
|
||||
/**
|
||||
* 异步操作任务调度线程池
|
||||
*/
|
||||
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
|
||||
private volatile ScheduledExecutorService executor;
|
||||
|
||||
/**
|
||||
* 单例模式
|
||||
@@ -35,14 +35,60 @@ public class AsyncManager
|
||||
return me;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取线程池执行器(延迟初始化)
|
||||
*/
|
||||
private ScheduledExecutorService getExecutor()
|
||||
{
|
||||
if (executor == null)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (executor == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查Spring上下文是否已经初始化
|
||||
if (SpringUtils.getApplicationContext() != null)
|
||||
{
|
||||
executor = SpringUtils.getBean("scheduledExecutorService");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Spring上下文未初始化,创建临时线程池
|
||||
executor = java.util.concurrent.Executors.newScheduledThreadPool(10);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// 如果获取失败,创建临时线程池
|
||||
System.err.println("Failed to get scheduledExecutorService bean, creating temporary executor: " + e.getMessage());
|
||||
executor = java.util.concurrent.Executors.newScheduledThreadPool(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
*
|
||||
*
|
||||
* @param task 任务
|
||||
*/
|
||||
public void execute(TimerTask task)
|
||||
{
|
||||
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
|
||||
ScheduledExecutorService exec = getExecutor();
|
||||
if (exec != null)
|
||||
{
|
||||
exec.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果线程池不可用,直接在当前线程执行
|
||||
System.err.println("Executor is null, running task in current thread");
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,6 +96,9 @@ public class AsyncManager
|
||||
*/
|
||||
public void shutdown()
|
||||
{
|
||||
Threads.shutdownAndAwaitTermination(executor);
|
||||
if (executor != null)
|
||||
{
|
||||
Threads.shutdownAndAwaitTermination(executor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
package com.ruoyi.framework.web.service;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* CAS工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class CasUtils
|
||||
{
|
||||
public String validateTicketByUrl(String validateUrl, String ticket, String service)
|
||||
{
|
||||
if (StringUtils.isEmpty(validateUrl) || StringUtils.isEmpty(ticket) || StringUtils.isEmpty(service))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
String url = validateUrl
|
||||
+ (validateUrl.contains("?") ? "&" : "?")
|
||||
+ "ticket=" + URLEncoder.encode(ticket, StandardCharsets.UTF_8.toString())
|
||||
+ "&service=" + URLEncoder.encode(service, StandardCharsets.UTF_8.toString());
|
||||
String response = sendHttpRequest(url);
|
||||
return parseUsername(response);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 验证CAS票据
|
||||
*
|
||||
* @param casServerUrl CAS服务器地址
|
||||
* @param ticket CAS票据
|
||||
* @param service 服务地址
|
||||
* @return 用户名,验证失败返回null
|
||||
*/
|
||||
public String validateTicket(String casServerUrl, String ticket, String service)
|
||||
{
|
||||
if (StringUtils.isEmpty(casServerUrl) || StringUtils.isEmpty(ticket) || StringUtils.isEmpty(service))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 构建验证URL
|
||||
String validateUrl = casServerUrl + "/serviceValidate"
|
||||
+ "?ticket=" + URLEncoder.encode(ticket, StandardCharsets.UTF_8.toString())
|
||||
+ "&service=" + URLEncoder.encode(service, StandardCharsets.UTF_8.toString());
|
||||
|
||||
// 发送HTTP请求验证票据
|
||||
String response = sendHttpRequest(validateUrl);
|
||||
|
||||
// 解析响应获取用户名
|
||||
return parseUsername(response);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP请求
|
||||
*
|
||||
* @param urlString 请求URL
|
||||
* @return 响应内容
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private String sendHttpRequest(String urlString) throws IOException
|
||||
{
|
||||
URL url = new URL(urlString);
|
||||
HttpURLConnection connection = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (urlString.startsWith("https"))
|
||||
{
|
||||
// 配置HTTPS连接,忽略SSL证书验证
|
||||
HttpsURLConnection httpsConnection = (HttpsURLConnection) url.openConnection();
|
||||
httpsConnection.setSSLSocketFactory(createTrustAllSSLContext().getSocketFactory());
|
||||
httpsConnection.setHostnameVerifier((hostname, session) -> true);
|
||||
connection = httpsConnection;
|
||||
}
|
||||
else
|
||||
{
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(10000);
|
||||
connection.setReadTimeout(10000);
|
||||
|
||||
// 读取响应
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)))
|
||||
{
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
response.append(line).append("\n");
|
||||
}
|
||||
return response.toString();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (connection != null)
|
||||
{
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建信任所有证书的SSL上下文
|
||||
*
|
||||
* @return SSL上下文
|
||||
*/
|
||||
private SSLContext createTrustAllSSLContext()
|
||||
{
|
||||
try
|
||||
{
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, new TrustManager[]
|
||||
{
|
||||
new X509TrustManager()
|
||||
{
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers()
|
||||
{
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
return sslContext;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("Failed to create SSL context", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析CAS响应获取用户名
|
||||
*
|
||||
* @param response CAS服务器响应
|
||||
* @return 用户名,解析失败返回null
|
||||
*/
|
||||
private String parseUsername(String response)
|
||||
{
|
||||
if (StringUtils.isEmpty(response))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查是否验证成功
|
||||
if (!response.contains("<cas:authenticationSuccess>"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 提取用户名
|
||||
String userTag = "<cas:user>";
|
||||
String userEndTag = "</cas:user>";
|
||||
|
||||
int startIndex = response.indexOf(userTag);
|
||||
if (startIndex == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
startIndex += userTag.length();
|
||||
int endIndex = response.indexOf(userEndTag, startIndex);
|
||||
if (endIndex == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.substring(startIndex, endIndex).trim();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.ruoyi.framework.web.service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
@@ -31,12 +32,11 @@ import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 登录校验方法
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class SysLoginService
|
||||
{
|
||||
public class SysLoginService {
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@@ -45,55 +45,59 @@ public class SysLoginService
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@Value("${cas.server.url:}")
|
||||
private String casServerUrl;
|
||||
|
||||
@Autowired
|
||||
private SysPermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
private CasUtils casUtils;
|
||||
|
||||
/**
|
||||
* 登录验证
|
||||
*
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @param code 验证码
|
||||
* @param uuid 唯一标识
|
||||
* @param code 验证码
|
||||
* @param uuid 唯一标识
|
||||
* @return 结果
|
||||
*/
|
||||
public String login(String username, String password, String code, String uuid)
|
||||
{
|
||||
public String login(String username, String password, String code, String uuid) {
|
||||
// 验证码校验
|
||||
validateCaptcha(username, code, uuid);
|
||||
// 登录前置校验
|
||||
loginPreCheck(username, password);
|
||||
// 用户验证
|
||||
Authentication authentication = null;
|
||||
try
|
||||
{
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
|
||||
try {
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,
|
||||
password);
|
||||
AuthenticationContextHolder.setContext(authenticationToken);
|
||||
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
|
||||
authentication = authenticationManager.authenticate(authenticationToken);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e instanceof BadCredentialsException)
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
|
||||
} catch (Exception e) {
|
||||
if (e instanceof BadCredentialsException) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
|
||||
MessageUtils.message("user.password.not.match")));
|
||||
throw new UserPasswordNotMatchException();
|
||||
}
|
||||
else
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
|
||||
} else {
|
||||
AsyncManager.me()
|
||||
.execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
} finally {
|
||||
AuthenticationContextHolder.clearContext();
|
||||
}
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS,
|
||||
MessageUtils.message("user.login.success")));
|
||||
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
||||
recordLoginInfo(loginUser.getUserId());
|
||||
// 生成token
|
||||
@@ -101,29 +105,108 @@ public class SysLoginService
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param code 验证码
|
||||
* @param uuid 唯一标识
|
||||
* CAS登录验证
|
||||
*
|
||||
* @param ticket CAS票据
|
||||
* @param service 服务地址
|
||||
* @return 结果
|
||||
*/
|
||||
public void validateCaptcha(String username, String code, String uuid)
|
||||
{
|
||||
public String casLogin(String ticket, String service) {
|
||||
String validateUrl = configService.selectConfigByKey("cas.validate.url");
|
||||
String casServerUrl = configService.selectConfigByKey("cas.server.url");
|
||||
if (StringUtils.isEmpty(validateUrl) && StringUtils.isEmpty(casServerUrl)) {
|
||||
throw new ServiceException("CAS服务器地址未配置");
|
||||
}
|
||||
|
||||
// 如果服务地址包含查询参数,提取基础地址用于CAS验证
|
||||
String baseService = service;
|
||||
int queryIndex = service.indexOf('?');
|
||||
if (queryIndex > 0) {
|
||||
baseService = service.substring(0, queryIndex);
|
||||
}
|
||||
|
||||
String username = StringUtils.isEmpty(validateUrl)
|
||||
? casUtils.validateTicket(casServerUrl, ticket, baseService)
|
||||
: casUtils.validateTicketByUrl(validateUrl, ticket, baseService);
|
||||
if (StringUtils.isEmpty(username)) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "CAS票据验证失败"));
|
||||
throw new ServiceException("CAS票据验证失败");
|
||||
}
|
||||
|
||||
// 用户验证
|
||||
Authentication authentication = null;
|
||||
try {
|
||||
// 创建认证令牌,CAS登录不需要密码验证
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,
|
||||
null);
|
||||
AuthenticationContextHolder.setContext(authenticationToken);
|
||||
|
||||
// 通过用户名加载用户信息
|
||||
LoginUser loginUser = loadUserByUsername(username);
|
||||
if (loginUser == null) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户不存在"));
|
||||
throw new ServiceException("用户不存在");
|
||||
}
|
||||
|
||||
// 创建认证对象
|
||||
authentication = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
|
||||
} catch (Exception e) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
|
||||
throw new ServiceException(e.getMessage());
|
||||
} finally {
|
||||
AuthenticationContextHolder.clearContext();
|
||||
}
|
||||
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS,
|
||||
MessageUtils.message("user.login.success")));
|
||||
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
||||
recordLoginInfo(loginUser.getUserId());
|
||||
// 生成token
|
||||
return tokenService.createToken(loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过用户名加载用户信息
|
||||
*
|
||||
* @param username 用户名
|
||||
* @return 登录用户信息
|
||||
*/
|
||||
private LoginUser loadUserByUsername(String username) {
|
||||
SysUser user = userService.selectUserByUserName(username);
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (UserConstants.USER_DISABLE.equals(user.getStatus())) {
|
||||
throw new ServiceException("用户已被停用,请联系管理员");
|
||||
}
|
||||
|
||||
return new LoginUser(user.getUserId(), user.getDeptId(), user, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param code 验证码
|
||||
* @param uuid 唯一标识
|
||||
* @return 结果
|
||||
*/
|
||||
public void validateCaptcha(String username, String code, String uuid) {
|
||||
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
||||
if (captchaEnabled)
|
||||
{
|
||||
if (captchaEnabled) {
|
||||
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
|
||||
String captcha = redisCache.getCacheObject(verifyKey);
|
||||
if (captcha == null)
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
|
||||
if (captcha == null) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
|
||||
MessageUtils.message("user.jcaptcha.expire")));
|
||||
throw new CaptchaExpireException();
|
||||
}
|
||||
redisCache.deleteObject(verifyKey);
|
||||
if (!code.equalsIgnoreCase(captcha))
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
|
||||
if (!code.equalsIgnoreCase(captcha)) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
|
||||
MessageUtils.message("user.jcaptcha.error")));
|
||||
throw new CaptchaException();
|
||||
}
|
||||
}
|
||||
@@ -131,36 +214,36 @@ public class SysLoginService
|
||||
|
||||
/**
|
||||
* 登录前置校验
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param password 用户密码
|
||||
*/
|
||||
public void loginPreCheck(String username, String password)
|
||||
{
|
||||
public void loginPreCheck(String username, String password) {
|
||||
// 用户名或密码为空 错误
|
||||
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
|
||||
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
|
||||
AsyncManager.me().execute(
|
||||
AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
|
||||
throw new UserNotExistsException();
|
||||
}
|
||||
// 密码如果不在指定范围内 错误
|
||||
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|
||||
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
|
||||
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
|
||||
MessageUtils.message("user.password.not.match")));
|
||||
throw new UserPasswordNotMatchException();
|
||||
}
|
||||
// 用户名不在指定范围内 错误
|
||||
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|
||||
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
|
||||
|| username.length() > UserConstants.USERNAME_MAX_LENGTH) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
|
||||
MessageUtils.message("user.password.not.match")));
|
||||
throw new UserPasswordNotMatchException();
|
||||
}
|
||||
// IP黑名单校验
|
||||
String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
|
||||
if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
|
||||
{
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
|
||||
if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) {
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
|
||||
MessageUtils.message("login.blocked")));
|
||||
throw new BlackListException();
|
||||
}
|
||||
}
|
||||
@@ -170,8 +253,7 @@ public class SysLoginService
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
public void recordLoginInfo(Long userId)
|
||||
{
|
||||
public void recordLoginInfo(Long userId) {
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUserId(userId);
|
||||
sysUser.setLoginIp(IpUtils.getIpAddr());
|
||||
|
||||
3
ruoyi-framework/target/maven-archiver/pom.properties
Normal file
3
ruoyi-framework/target/maven-archiver/pom.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
artifactId=ruoyi-framework
|
||||
groupId=com.ruoyi
|
||||
version=3.8.8
|
||||
@@ -0,0 +1,51 @@
|
||||
com\ruoyi\framework\config\CaptchaConfig.class
|
||||
com\ruoyi\framework\config\ServerConfig.class
|
||||
com\ruoyi\framework\web\service\SysLoginService.class
|
||||
com\ruoyi\framework\security\handle\AuthenticationEntryPointImpl.class
|
||||
com\ruoyi\framework\security\context\AuthenticationContextHolder.class
|
||||
com\ruoyi\framework\web\service\PermissionService.class
|
||||
com\ruoyi\framework\web\domain\server\Cpu.class
|
||||
com\ruoyi\framework\web\domain\server\Mem.class
|
||||
com\ruoyi\framework\config\MyBatisConfig.class
|
||||
com\ruoyi\framework\config\DruidConfig$1.class
|
||||
com\ruoyi\framework\manager\factory\AsyncFactory$1.class
|
||||
com\ruoyi\framework\manager\factory\AsyncFactory.class
|
||||
com\ruoyi\framework\web\service\SysRegisterService.class
|
||||
com\ruoyi\framework\config\FilterConfig.class
|
||||
com\ruoyi\framework\web\service\CasUtils$1.class
|
||||
com\ruoyi\framework\manager\ShutdownManager.class
|
||||
com\ruoyi\framework\datasource\DynamicDataSource.class
|
||||
com\ruoyi\framework\config\properties\PermitAllUrlProperties.class
|
||||
com\ruoyi\framework\web\service\CasUtils.class
|
||||
com\ruoyi\framework\web\service\SysPermissionService.class
|
||||
com\ruoyi\framework\web\exception\GlobalExceptionHandler.class
|
||||
com\ruoyi\framework\config\ThreadPoolConfig$1.class
|
||||
com\ruoyi\framework\manager\factory\AsyncFactory$2.class
|
||||
com\ruoyi\framework\config\SecurityConfig.class
|
||||
com\ruoyi\framework\web\service\UserDetailsServiceImpl.class
|
||||
com\ruoyi\framework\aspectj\RateLimiterAspect.class
|
||||
com\ruoyi\framework\config\KaptchaTextCreator.class
|
||||
com\ruoyi\framework\config\ResourcesConfig.class
|
||||
com\ruoyi\framework\datasource\DynamicDataSourceContextHolder.class
|
||||
com\ruoyi\framework\interceptor\RepeatSubmitInterceptor.class
|
||||
com\ruoyi\framework\web\domain\server\Jvm.class
|
||||
com\ruoyi\framework\config\properties\DruidProperties.class
|
||||
com\ruoyi\framework\aspectj\DataSourceAspect.class
|
||||
com\ruoyi\framework\aspectj\LogAspect.class
|
||||
com\ruoyi\framework\config\I18nConfig.class
|
||||
com\ruoyi\framework\config\FastJson2JsonRedisSerializer.class
|
||||
com\ruoyi\framework\web\domain\server\SysFile.class
|
||||
com\ruoyi\framework\manager\AsyncManager.class
|
||||
com\ruoyi\framework\web\service\SysPasswordService.class
|
||||
com\ruoyi\framework\interceptor\impl\SameUrlDataInterceptor.class
|
||||
com\ruoyi\framework\security\context\PermissionContextHolder.class
|
||||
com\ruoyi\framework\security\filter\JwtAuthenticationTokenFilter.class
|
||||
com\ruoyi\framework\web\service\TokenService.class
|
||||
com\ruoyi\framework\config\ThreadPoolConfig.class
|
||||
com\ruoyi\framework\config\DruidConfig.class
|
||||
com\ruoyi\framework\web\domain\server\Sys.class
|
||||
com\ruoyi\framework\config\ApplicationConfig.class
|
||||
com\ruoyi\framework\config\RedisConfig.class
|
||||
com\ruoyi\framework\web\domain\Server.class
|
||||
com\ruoyi\framework\security\handle\LogoutSuccessHandlerImpl.class
|
||||
com\ruoyi\framework\aspectj\DataScopeAspect.class
|
||||
@@ -0,0 +1,46 @@
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\FilterConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\manager\factory\AsyncFactory.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\interceptor\RepeatSubmitInterceptor.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\MyBatisConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\properties\DruidProperties.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\domain\server\Sys.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\aspectj\DataSourceAspect.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\domain\server\Jvm.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\ThreadPoolConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\RedisConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\domain\server\Mem.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\domain\Server.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\datasource\DynamicDataSource.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\SysPasswordService.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\interceptor\impl\SameUrlDataInterceptor.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\security\filter\JwtAuthenticationTokenFilter.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\ApplicationConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\domain\server\Cpu.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\SysPermissionService.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\security\context\AuthenticationContextHolder.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\security\handle\AuthenticationEntryPointImpl.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\security\handle\LogoutSuccessHandlerImpl.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\properties\PermitAllUrlProperties.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\security\context\PermissionContextHolder.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\manager\AsyncManager.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\ServerConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\PermissionService.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\DruidConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\TokenService.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\aspectj\RateLimiterAspect.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\SysRegisterService.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\aspectj\LogAspect.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\datasource\DynamicDataSourceContextHolder.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\ResourcesConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\FastJson2JsonRedisSerializer.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\CaptchaConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\I18nConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\manager\ShutdownManager.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\CasUtils.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\KaptchaTextCreator.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\config\SecurityConfig.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\domain\server\SysFile.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\UserDetailsServiceImpl.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\aspectj\DataScopeAspect.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\SysLoginService.java
|
||||
D:\code\pasd_V1.0\pasd_java\ruoyi-framework\src\main\java\com\ruoyi\framework\web\exception\GlobalExceptionHandler.java
|
||||
Reference in New Issue
Block a user