oss 单点

This commit is contained in:
Lishundong
2025-10-11 16:02:04 +08:00
parent 0076eeeb48
commit db413c57aa
34 changed files with 771 additions and 125 deletions

View File

@@ -5,6 +5,10 @@ import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.core.domain.model.LoginSiteUser;
import com.ruoyi.common.utils.SiteSecurityUtils;
import com.ruoyi.framework.web.service.TokenSiteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -27,11 +31,14 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
@Autowired
private TokenService tokenService;
@Autowired
private TokenSiteService tokenSiteService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException
{
LoginUser loginUser = tokenService.getLoginUser(request);
LoginSiteUser loginSiteUser = tokenSiteService.getLoginSiteUser(request);
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
{
tokenService.verifyToken(loginUser);
@@ -39,6 +46,13 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
if (StringUtils.isNotNull(loginSiteUser) && StringUtils.isNull(SiteSecurityUtils.getAuthentication()))
{
tokenSiteService.verifyToken(loginSiteUser);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginSiteUser, null,loginSiteUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
chain.doFilter(request, response);
}
}

View File

@@ -4,6 +4,9 @@ import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.core.domain.model.LoginSiteUser;
import com.ruoyi.framework.web.service.TokenSiteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
@@ -29,7 +32,8 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
{
@Autowired
private TokenService tokenService;
@Autowired
private TokenSiteService tokenSiteService;
/**
* 退出处理
*
@@ -48,6 +52,15 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
// 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
}
LoginSiteUser loginSiteUser = tokenSiteService.getLoginSiteUser(request);
if (StringUtils.isNotNull(loginSiteUser))
{
String userName = loginSiteUser.getUsername();
// 删除用户缓存记录
tokenSiteService.delLoginSiteUser(loginSiteUser.getToken());
// 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
}
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success"))));
}
}

View File

@@ -1,6 +1,9 @@
package com.ruoyi.framework.web.service;
import javax.annotation.Resource;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.core.domain.model.LoginSiteUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
@@ -52,6 +55,8 @@ public class SysLoginService
@Autowired
private ISysConfigService configService;
@Autowired
private TokenSiteService tokenSiteService;
/**
* 登录验证
*
@@ -99,41 +104,24 @@ public class SysLoginService
// 生成token
return tokenService.createToken(loginUser);
}
//模拟登录
public String loginApp(String username, String password)
{
// 登录前置校验
loginPreCheck(username, password);
// 用户验证
Authentication authentication = null;
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")));
throw new UserPasswordNotMatchException();
}
else
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
}
finally
{
AuthenticationContextHolder.clearContext();
}
AppUser appUser = userService.selectAppUserById(1L);
LoginSiteUser loginSiteUser = new LoginSiteUser();
loginSiteUser.setUserId(appUser.getUserId());
loginSiteUser.setUser(appUser);
recordLoginInfo(appUser);
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
recordLoginInfo(appUser);
// 生成token
return tokenService.createToken(loginUser);
return tokenSiteService.createToken(loginSiteUser);
}
//单点登录
public String loginOss(String ticket)
{
return "tokenService.createToken(loginUser)";
}
/**
* 校验验证码
@@ -163,7 +151,15 @@ public class SysLoginService
}
}
}
public void recordLoginInfo(AppUser user)
{
AppUser sysUser = new AppUser();
sysUser.setUserId(user.getUserId());
sysUser.setLoginIp(IpUtils.getIpAddr());
sysUser.setLoginDate(DateUtils.getNowDate());
sysUser.setUpdateBy(user.getName());
// userService.updateSiteUser(sysUser);
}
/**
* 登录前置校验
* @param username 用户名

View File

@@ -0,0 +1,242 @@
package com.ruoyi.framework.web.service;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginSiteUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* token验证处理
*
* @author ruoyi
*/
@Component
public class TokenSiteService
{
private static final Logger log = LoggerFactory.getLogger(TokenSiteService.class);
// 令牌自定义标识
@Value("${token.header}")
private String header;
// 令牌秘钥
@Value("${token.secret}")
private String secret;
@Value("${token.expireTime}")
private int expireTime;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
@Autowired
private RedisCache redisCache;
/**
* 获取用户身份信息
*
* @return 用户信息
*/
public LoginSiteUser getLoginSiteUser(HttpServletRequest request)
{
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token))
{
try
{
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.APP_LOGIN_USER_KEY);
Integer userID = (Integer) claims.get(Constants.APP_LOGIN_USER_ID);
String userKey = getTokenKey(uuid, String.valueOf(userID));
LoginSiteUser user = redisCache.getCacheObject(userKey);
return user;
}
catch (Exception e)
{
log.error("获取用户信息异常'{}'", e.getMessage());
}
}
return null;
}
/**
* 设置用户身份信息
*/
public void setLoginSiteUser(LoginSiteUser LoginSiteUser)
{
if (StringUtils.isNotNull(LoginSiteUser) && StringUtils.isNotEmpty(LoginSiteUser.getToken()))
{
refreshToken(LoginSiteUser);
}
}
/**
* 删除用户身份信息
*/
public void delLoginSiteUser(String token)
{
if (StringUtils.isNotEmpty(token))
{
String userKey = getTokenKey(token);
redisCache.deleteObject(userKey);
}
}
/**
* 创建令牌
*
* @param LoginSiteUser 用户信息
* @return 令牌
*/
public String createToken(LoginSiteUser LoginSiteUser)
{
String token = IdUtils.fastUUID();
LoginSiteUser.setToken(token);
setUserAgent(LoginSiteUser);
refreshToken(LoginSiteUser);
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.APP_LOGIN_USER_KEY, token);
claims.put(Constants.APP_LOGIN_USER_ID, LoginSiteUser.getUserId());
// 当前时间 + 30 分钟
long currentTimeMillis = System.currentTimeMillis();
long expireTimeMillis = currentTimeMillis + ((long) expireTime * 60 * 1000); // 30分钟 = 1800000 毫秒
long expireTimeSeconds = expireTimeMillis / 1000; // 转换为秒(时间戳)
claims.put(Constants.EXP, expireTimeSeconds);
return createToken(claims);
}
/**
* 验证令牌有效期相差不足20分钟自动刷新缓存
*
* @param LoginSiteUser
* @return 令牌
*/
public void verifyToken(LoginSiteUser LoginSiteUser)
{
long expireTime = LoginSiteUser.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
{
refreshToken(LoginSiteUser);
}
}
/**
* 刷新令牌有效期
*
* @param LoginSiteUser 登录信息
*/
public void refreshToken(LoginSiteUser LoginSiteUser)
{
LoginSiteUser.setLoginTime(System.currentTimeMillis());
LoginSiteUser.setExpireTime(LoginSiteUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将LoginSiteUser缓存
String userKey = getTokenKey(LoginSiteUser.getToken(), String.valueOf(LoginSiteUser.getUserId()));
redisCache.setCacheObject(userKey, LoginSiteUser, expireTime, TimeUnit.MINUTES);
}
/**
* 设置用户代理信息
*
* @param LoginSiteUser 登录信息
*/
public void setUserAgent(LoginSiteUser LoginSiteUser)
{
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = IpUtils.getIpAddr();
LoginSiteUser.setIpaddr(ip);
LoginSiteUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
LoginSiteUser.setBrowser(userAgent.getBrowser().getName());
LoginSiteUser.setOs(userAgent.getOperatingSystem().getName());
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims)
{
String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private Claims parseToken(String token)
{
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
public String getUsernameFromToken(String token)
{
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @param request
* @return token
*/
private String getToken(HttpServletRequest request)
{
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
{
token = token.replace(Constants.TOKEN_PREFIX, "");
}
return token;
}
private String getTokenKey(String uuid,String userId)
{
return CacheConstants.SITE_LOGIN_TOKEN_KEY +userId+":" +uuid;
}
private String getTokenKey(String uuid)
{
return CacheConstants.SITE_LOGIN_TOKEN_KEY + uuid;
}
}