Implementing Multi-Device Token Storage and Validation with Spring Boot, Redis, and Vue
This article explains how to design and implement a token generation, storage, and verification system for both PC and mobile clients in a distributed microservice architecture, using Spring Boot, Redis, custom annotations, AOP aspects, and Vue front‑end integration.
Introduction: In a distributed microservice scenario, token validation and single sign‑on are needed for both PC and mobile clients.
Token storage entity: a LoginToken class with fields PcLoginToken, MobileLoginToken, LoginIP is stored in Redis.
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginToken {
private String PcLoginToken;
private String MobileLoginToken;
private String LoginIP;
}Login service: generates token, stores it in Redis with a 7‑day expiry, and returns it to the client.
@Service
public class loginServiceImpl implements LoginService {
@Autowired UserService userService;
@Autowired RedisUtils redisUtils;
@Override
public R Login(LoginEntity entity) {
// ... (core login logic, token generation, Redis storage)
}
}Enum BizCodeEnum defines response codes; custom exception classes handle login errors such as bad parameters, unknown login type, and token mismatch.
public class BadLoginParamsException extends Exception {
public BadLoginParamsException() {}
public BadLoginParamsException(String message) { super(message); }
}Client‑side storage: a Vue component stores the token in localStorage with an expiration helper to automatically remove expired entries.
Storage.prototype.setExpire = (key, value, expire) => {
let obj = { data: value, time: Date.now(), expire: expire };
localStorage.setItem(key, JSON.stringify(obj));
};
Storage.prototype.getExpire = key => {
let val = localStorage.getItem(key);
if (!val) return null;
val = JSON.parse(val);
if (Date.now() - val.time > val.expire) { localStorage.removeItem(key); return null; }
return val.data;
};Token verification flow: the front‑end sends loginToken, userid, and loginType in request headers; the back‑end validates them via a custom @NeedLogin annotation and an AOP aspect.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedLogin { String value() default ""; } public class VerificationAspect {
@Autowired RedisUtils redisUtils;
@Pointcut("@annotation(com.huterox.common.holeAnnotation.NeedLogin)")
public void verification() {}
@Around("verification()")
public Object verification(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String loginType = request.getHeader("loginType");
String userid = request.getHeader("userid");
String tokenUser = request.getHeader("loginToken");
String tokenKey = RedisTransKey.getTokenKey(userid + ":" + loginType);
if (tokenUser == null || userid == null || loginType == null) throw new BadLoginParamsException();
if (!redisUtils.hasKey(tokenKey)) throw new NotLoginException();
Object o = redisUtils.get(tokenKey);
LoginToken loginToken = JSON.parseObject(o.toString(), LoginToken.class);
if (loginType.equals(LoginType.PcType) && !loginToken.getPcLoginToken().equals(tokenUser))
throw new BadLoginTokenException();
if (loginType.equals(LoginType.MobileType) && !loginToken.getMobileLoginToken().equals(tokenUser))
throw new BadLoginTokenException();
return pjp.proceed();
}
}The controller methods annotated with @NeedLogin trigger the aspect, ensuring that only requests with a valid token stored in Redis can access protected PC or mobile endpoints, completing a secure token‑based authentication mechanism.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
