| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- package com.ruoyi.system.utils;
- import com.auth0.jwt.JWT;
- import com.auth0.jwt.algorithms.Algorithm;
- import com.ruoyi.common.constant.CacheConstants;
- import com.ruoyi.common.core.domain.AjaxResult;
- import com.ruoyi.common.core.redis.RedisCache;
- import jakarta.servlet.http.HttpServletRequest;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.reflect.MethodSignature;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
- import java.lang.reflect.Method;
- import java.util.Date;
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import static org.junit.jupiter.api.Assertions.assertSame;
- import static org.mockito.ArgumentMatchers.anyString;
- import static org.mockito.Mockito.mock;
- import static org.mockito.Mockito.never;
- import static org.mockito.Mockito.verify;
- import static org.mockito.Mockito.when;
- /**
- * 单设备登录(2026-09-22)会话校验切面测试:
- * 新格式会话 token(jti 含冒号)必须存在 Redis 会话,被顶号/登出删除后即 401;
- * 无 Redis 会话的旧 token 和无 jti token 均拒绝。
- */
- class AuthAspectTest {
- private RedisCache redisCache;
- private HttpServletRequest request;
- private ProceedingJoinPoint joinPoint;
- private MethodSignature signature;
- private AuthAspect aspect;
- @BeforeEach
- void setUp() {
- redisCache = mock(RedisCache.class);
- request = mock(HttpServletRequest.class);
- joinPoint = mock(ProceedingJoinPoint.class);
- signature = mock(MethodSignature.class);
- aspect = new AuthAspect(redisCache);
- aspect.setHttpServletRequest(request);
- when(joinPoint.getSignature()).thenReturn(signature);
- }
- /** 手工签发新格式会话 token:jti 含冒号但不落 Redis,会话存在性由 redisCache 桩控制 */
- private String colonJtiToken(String jti) {
- return JWT.create()
- .withClaim("id", "936")
- .withExpiresAt(new Date(System.currentTimeMillis() + 60_000))
- .withJWTId(jti)
- .sign(Algorithm.HMAC256("TEST-AUTH-TOKEN"));
- }
- @Test
- void deletedSessionIsRejectedBeforeController() throws Throwable {
- String jti = CacheConstants.USER_TOKEN_KEY + "936:deleted-session";
- prepareInvocation("endpoint", colonJtiToken(jti));
- when(redisCache.hasKey(jti)).thenReturn(false);
- Object result = aspect.around(joinPoint);
- assertEquals(401, ((AjaxResult) result).get("code"), "会话被删(被顶号/登出)应返回 401");
- verify(joinPoint, never()).proceed();
- }
- @Test
- void liveSessionProceedsAndExposesTrustedIdentity() throws Throwable {
- String jti = CacheConstants.USER_TOKEN_KEY + "936:live-session";
- prepareInvocation("endpoint", colonJtiToken(jti));
- when(redisCache.hasKey(jti)).thenReturn(true);
- Object expected = new Object();
- when(joinPoint.proceed()).thenReturn(expected);
- Object actual = aspect.around(joinPoint);
- assertSame(expected, actual);
- verify(request).setAttribute(AuthContext.USER_ID_ATTRIBUTE, 936L);
- verify(request).setAttribute(AuthContext.JTI_ATTRIBUTE, jti);
- }
- @Test
- void legacyNoColonJtiWithoutSessionIsRejected() throws Throwable {
- // 历史无会话重载 JwtUtil.token(id, userName) 签发:jti 为纯 UUID,不含冒号
- prepareInvocation("endpoint", JwtUtil.token("936", "user"));
- Object actual = aspect.around(joinPoint);
- assertEquals(401, ((AjaxResult) actual).get("code"));
- verify(joinPoint, never()).proceed();
- }
- @Test
- void tokenWithoutJtiIsRejected() throws Throwable {
- String token = JWT.create()
- .withClaim("id", "936")
- .withExpiresAt(new Date(System.currentTimeMillis() + 60_000))
- .sign(Algorithm.HMAC256("TEST-AUTH-TOKEN"));
- prepareInvocation("endpoint", token);
- Object actual = aspect.around(joinPoint);
- assertEquals(401, ((AjaxResult) actual).get("code"));
- verify(redisCache, never()).hasKey(anyString());
- verify(joinPoint, never()).proceed();
- }
- @Test
- void invalidSignatureRejectedBeforeSessionLookup() throws Throwable {
- prepareInvocation("endpoint", "not-a-jwt");
- Object result = aspect.around(joinPoint);
- assertEquals(401, ((AjaxResult) result).get("code"));
- verify(redisCache, never()).hasKey(anyString());
- verify(joinPoint, never()).proceed();
- }
- private void prepareInvocation(String methodName, String token) throws Exception {
- Method method = SecuredMethods.class.getDeclaredMethod(methodName);
- when(signature.getMethod()).thenReturn(method);
- when(request.getHeader("token")).thenReturn(token);
- }
- static class SecuredMethods {
- @Auth
- public void endpoint() {
- }
- }
- }
|