MST

星途 面试题库

面试题:微服务架构下Spring Cloud分布式系统中如何实现基于Token的认证机制

在Spring Cloud微服务架构的分布式系统里,描述一下如何利用Token实现用户认证。请阐述具体的技术选型、关键代码片段以及Token在各微服务间传递的流程。
45.9万 热度难度
后端开发微服务架构

知识考点

AI 面试

面试题答案

一键面试

技术选型

  1. 生成与验证Token:通常选用JSON Web Token(JWT)。JWT是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间以JSON对象的形式安全地传输信息。在Java中,常用的库有jjwt
  2. 存储用户信息:可以使用关系型数据库(如MySQL)或NoSQL数据库(如Redis)。如果选择Redis,因其高性能的读写能力,非常适合存储与用户认证相关的短期数据,如用户登录状态等。

关键代码片段

  1. 生成Token
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    public class TokenUtil {
        private static final String SECRET_KEY = "your_secret_key";
        public static String generateToken(String username) {
            Map<String, Object> claims = new HashMap<>();
            claims.put("sub", username);
            claims.put("iat", new Date());
            claims.put("exp", new Date(System.currentTimeMillis() + 10 * 60 * 1000));// 10分钟过期
            return Jwts.builder()
                   .setClaims(claims)
                   .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                   .compact();
        }
    }
    
  2. 验证Token
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureException;
    public class TokenUtil {
        private static final String SECRET_KEY = "your_secret_key";
        public static boolean validateToken(String token) {
            try {
                Claims claims = Jwts.parser()
                       .setSigningKey(SECRET_KEY)
                       .parseClaimsJws(token)
                       .getBody();
                Date expiration = claims.getExpiration();
                return!expiration.before(new Date());
            } catch (SignatureException | IllegalArgumentException e) {
                return false;
            }
        }
    }
    

Token在各微服务间传递的流程

  1. 用户登录
    • 用户在客户端输入用户名和密码,发送登录请求到认证服务微服务。
    • 认证服务微服务验证用户输入的用户名和密码是否正确。如果正确,调用TokenUtil.generateToken方法生成Token,并将Token返回给客户端。
  2. 客户端请求其他微服务
    • 客户端在收到Token后,在后续每次请求其他微服务时,将Token放在HTTP请求的Authorization头中,格式为Bearer {token}。例如:Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VybmFtZSIsImlhdCI6MTYxNjM0MjQ1NSwiZXhwIjoxNjE2MzQzMDU1fQ.Gz81Z20f4t05X8Gj758z5894754786547865
  3. 微服务接收请求并验证Token
    • 每个需要认证的微服务在接收到请求时,从Authorization头中提取Token。
    • 调用TokenUtil.validateToken方法验证Token的有效性。如果Token有效,则处理请求;如果无效,则返回未授权错误(如HTTP 401状态码)。
  4. 微服务间调用
    • 如果一个微服务需要调用另一个微服务,并且被调用的微服务也需要认证,调用方微服务需要将从客户端接收到的Token传递给被调用方微服务。可以在Feign等微服务调用工具中进行配置,使其在调用时自动带上Token。例如,在Feign的配置类中:
    import feign.RequestInterceptor;
    import feign.RequestTemplate;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    @Configuration
    public class FeignConfig {
        @Bean
        public RequestInterceptor requestInterceptor() {
            return new RequestInterceptor() {
                @Override
                public void apply(RequestTemplate template) {
                    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                    if (attributes!= null) {
                        String token = attributes.getRequest().getHeader("Authorization");
                        if (token!= null) {
                            template.header("Authorization", token);
                        }
                    }
                }
            };
        }
    }
    
    这样,在微服务间通过Feign调用时,Token会被自动传递,保证了整个分布式系统中认证状态的一致性。