详解用JWT对SpringCloud进行认证和鉴权

详解用JWT对SpringCloud进行认证和鉴权

什么是JWT

JWT (JSON Web Token) 是一种开放标准 (RFC 7519),它定义了一种简洁的、自包含的方式,用于在不同的系统之间传递安全信息。JWT 通常由 3 部分组成:头部 (header)、载荷 (payload)、签名 (signature)。其中,头部用于描述 JWT 的元数据,载荷是 JWT 中存放有效信息的地方,签名则是用于验证 JWT 真实性的。

JWT在Spring Cloud中的鉴权和认证

在微服务架构中,通常会有多个服务协同工作,因此需要对服务进行鉴权和认证,确保只有经过授权的用户才能访问相应的服务,这时就需要使用 JWT。

Spring Cloud 提供了多种 JWT 鉴权和认证的解决方案,其中最常用的是 Spring Security + JWT。具体实现步骤如下:

  1. 引入 Spring Security、JWT 相关依赖:

```xml

org.springframework.cloud
spring-cloud-starter-oauth2


io.jsonwebtoken
jjwt-api
0.11.2


io.jsonwebtoken
jjwt-impl
0.11.2
runtime


io.jsonwebtoken
jjwt-jackson
0.11.2
runtime

```

  1. 配置 Spring Security:

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Autowired
   private JwtTokenProvider jwtTokenProvider;

   @Override
   protected void configure(HttpSecurity http) throws Exception {
       http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
               .authorizeRequests().antMatchers("/login", "/register").permitAll().anyRequest().authenticated().and()
               .apply(new JwtConfigurer(jwtTokenProvider));
   }

}
```

  1. 实现 JwtTokenProvider 接口:

```java
public interface JwtTokenProvider {
String createToken(String subject, Map claims);

   Claims getClaims(String token);

   boolean validateToken(String token);

   String getUsername(String token);

   List<String> getRoles(String token);

   String resolveToken(HttpServletRequest request);

}
```

  1. 实现 JwtTokenProvider 接口的具体方法:

```java
@Component
public class JwtTokenProviderImpl implements JwtTokenProvider {

   private static final Logger logger = LoggerFactory.getLogger(JwtTokenProviderImpl.class);

   @Value("${jwt.secret}")
   private String secretKey;

   @Value("${jwt.token.validity}")
   private long validityInMilliseconds;

   @Override
   public String createToken(String subject, Map<String, Object> claims) {
       Date now = new Date();
       Date validity = new Date(now.getTime() + validityInMilliseconds);

       return Jwts.builder().setSubject(subject).setClaims(claims).setIssuedAt(now).setExpiration(validity)
               .signWith(SignatureAlgorithm.HS256, secretKey).compact();
   }

   @Override
   public Claims getClaims(String token) {
       return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
   }

   @Override
   public boolean validateToken(String token) {
       try {
           Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
           return true;
       } catch (JwtException | IllegalArgumentException e) {
           logger.error("Expired or invalid JWT token: {}", e.getMessage());
       }
       return false;
   }

   @Override
   public String getUsername(String token) {
       return getClaims(token).getSubject();
   }

   @Override
   @SuppressWarnings("unchecked")
   public List<String> getRoles(String token) {
       return (List<String>) getClaims(token).get("roles");
   }

   @Override
   public String resolveToken(HttpServletRequest request) {
       String bearerToken = request.getHeader("Authorization");
       if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
           return bearerToken.substring(7);
       }
       return null;
   }

}
```

  1. 实现 JwtConfigurer:

```java
public class JwtConfigurer extends SecurityConfigurerAdapter {

   private JwtTokenProvider jwtTokenProvider;

   public JwtConfigurer(JwtTokenProvider jwtTokenProvider) {
       this.jwtTokenProvider = jwtTokenProvider;
   }

   @Override
   public void configure(HttpSecurity http) throws Exception {
       JwtTokenFilter customFilter = new JwtTokenFilter(jwtTokenProvider);
       http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
   }

}
```

  1. 实现 JwtTokenFilter:

```java
public class JwtTokenFilter extends OncePerRequestFilter {

   private JwtTokenProvider jwtTokenProvider;

   public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
       this.jwtTokenProvider = jwtTokenProvider;
   }

   @Override
   protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
           throws ServletException, IOException {
       String token = jwtTokenProvider.resolveToken(request);
       if (token != null && jwtTokenProvider.validateToken(token)) {
           Authentication auth = jwtTokenProvider.getAuthentication(token);
           SecurityContextHolder.getContext().setAuthentication(auth);
       }
       filterChain.doFilter(request, response);
   }

}
```

示例1:使用Postman测试Spring Cloud中的JWT鉴权和认证

  1. 启动 Spring Cloud 中的服务,确保服务在本地运行,例如,服务的端口为 8080。

  2. 使用 Postman 发送 GET 请求时,先不进行 JWT认证。可以通过以下两种方式测试:

  3. 访问没有配置 JWT 鉴权和认证的接口,例如查询某个用户的基本信息。由于该接口没有访问权限限制,可以正常访问。

  4. 访问已经配置 JWT 鉴权和认证的接口,例如查询某个订单的详细信息。由于没有 JWT 认证(即没有传入有效的 JWT token),应返回 401 错误码。

  5. 使用 Postman 发送 POST 请求时,需要进行 JWT 认证。具体步骤如下:

  6. 以管理员身份登录,获取有效的 JWT token。

  7. 在 Postman 的请求头中设置 Authorization 字段,其值为 Bearer 后接上述获取的 JWT token。

  8. 发送包含有效 JWT token 的 POST 请求,例如新增商品信息。由于设置了 JWT 鉴权和认证,只有管理员身份的用户可以访问该接口,其他用户将被拒绝访问。

  9. 发送包含无效 JWT token 的 POST 请求,例如删除某个商品。由于 JWT 认证不通过,应返回 401 错误码。

示例2:使用Istio的JWT鉴权

  1. 部署 Istio 服务网格,可以参考官方文档:https://istio.io/latest/docs/setup/install/

  2. 部署 Spring Cloud 中的服务,并将服务注册到 Istio 中:

  3. 在 Spring Cloud 的服务配置文件中增加以下配置:

    yaml
    eureka:
    instance:
    metadataMap:
    istio:
    workloadLabels: "app=<your-spring-cloud-app>"

    其中,<your-spring-cloud-app> 为 Spring Cloud 服务的名称。

  4. 在 Istio 的 DestinationRule 配置中增加以下配置:

    yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
    name: <your-spring-cloud-app>-destination
    spec:
    host: <your-spring-cloud-app>
    trafficPolicy:
    tls:
    mode: DISABLE
    connectionPool:
    http:
    http1MaxPendingRequests: 1024
    maxRequestsPerConnection: 1024
    tcp:
    maxConnections: 1024

    其中,<your-spring-cloud-app> 为 Spring Cloud 服务的名称。

  5. 配置 Istio 中的 JWT 鉴权:

  6. 创建 JWT 证书:

    sh
    # 生成私钥
    openssl genrsa -out ./jwt.key 4096
    # 生成公钥
    openssl rsa -in ./jwt.key -pubout -out ./jwt.pub

    其中,jwt.key 为生成的私钥文件,jwt.pub 为生成的公钥文件。

  7. 创建 Istio 的 AuthorizationPolicy 配置:

    yaml
    apiVersion: security.istio.io/v1beta1
    kind: AuthorizationPolicy
    metadata:
    name: <your-spring-cloud-app>-authorization
    spec:
    selector:
    matchLabels:
    app: <your-spring-cloud-app>
    version: v1
    action: ALLOW
    rules:
    - from:
    - source:
    requestPrincipals: ["*"]
    to:
    - operation:
    methods: ["*"]

    其中,<your-spring-cloud-app> 为 Spring Cloud 服务的名称,v1 为服务的版本。

  8. 测试 JWT 鉴权:

  9. 使用 jwt-cli 工具,生成有效的 JWT token:

    sh
    # 生成包含 username 和 roles 的 JWT token
    jwt encode --secret <your-secret-key> --alg HS256 --sub <your-username> --claims roles=<your-roles>

    其中,<your-secret-key> 为自定义的密钥,<your-username> 为用户名,<your-roles> 为用户角色信息。

  10. 在 Postman 的请求头中设置 Authorization 字段,其值为 Bearer 后接上述生成的有效 JWT token。

  11. 发送 GET 请求,例如查询某个订单的详细信息。由于 JWT 鉴权和认证通过,可以正常访问该接口。

  12. 发送 GET 请求,例如查询某个用户的基本信息。由于未设置 JWT 鉴权和认证,可以正常访问该接口。

以上就是使用 JWT 对 Spring Cloud 进行认证和鉴权的详细攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解用JWT对SpringCloud进行认证和鉴权 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • java编程数据类型全面详解教程新手必入

    Java编程数据类型全面详解教程新手必入攻略 本文将为Java新手提供全面详细的Java数据类型教程,包括数据类型的定义、分类、使用方法等内容,帮助新手快速入门Java编程。 数据类型是什么? 数据类型是计算机语言中用来表示数据分类的一种分类方式。在Java编程中,数据类型用来声明变量的类型,以便编译器能够对变量进行正确处理。 Java数据类型分类 Java…

    Java 2023年5月23日
    00
  • 一文了解Java中record和lombok的使用对比

    一文了解Java中record和lombok的使用对比 record 和 Lombok 都是 Java 中提高开发效率的工具。它们的相似点是都可以通过简化代码的方式减少 Java 的样板代码。但它们基于的思想有所不同,record 是 Java 语言的一部分,而 Lombok 是一个库。在这篇文章中,我们将探讨这两种工具的不同之处和适用情况。 Record …

    Java 2023年5月26日
    00
  • 什么是对象的访问?

    对象的访问实际上指的是对对象中属性和方法的访问。在 JavaScript 中,对象是一个由属性名和属性值组成的集合,并且属性值可以包含基本数据类型、函数、甚至是其他对象等。 要访问对象的属性和方法,需要使用点操作符(.)或方括号操作符([])来访问对象属性和方法。其中,点操作符用于访问对象的属性,而方括号操作符可用于使用变量访问属性。 下面是一些常见的对象访…

    Java 2023年5月10日
    00
  • Java SpringBoot高级用法详解

    Java Spring Boot 高级用法详解 简介 Java Spring Boot 是一个基于Spring Framework的开源框架,它可以让我们快速开发Web应用程序。在基本使用之外,Spring Boot还有很多高级用法可以帮助开发人员更加灵活地应对各种复杂情况。 编写自定义starter 自定义starter可以让我们将一些通用代码打包成一个独…

    Java 2023年5月15日
    00
  • java 二维数组矩阵乘法的实现方法

    Java二维数组矩阵的乘法实现 矩阵的乘法是一种重要的运算,它是许多计算机程序中的基本操作之一。在Java中,我们可以使用二维数组来表示矩阵,并通过循环来实现矩阵的乘法运算。 矩阵乘法的基本原理 假设我们有两个矩阵A和B: A = [a11 a12 a13] [a21 a22 a23] B = [b11 b12] [b21 b22] [b31 b32] 这里…

    Java 2023年5月26日
    00
  • Spring如何处理注解的深入理解

    下面是关于“Spring如何处理注解的深入理解”的完整攻略,包含两个示例说明。 Spring如何处理注解的深入理解 Spring是一个非常流行的Java应用程序框架,它提供了一种全面的编程和配置模型,用于构建现代化的基于Java的企业应用程序。在Spring中,注解是一种非常重要的机制,它可以帮助我们更加方便地配置和管理应用程序。本文将深入探讨Spring如…

    Java 2023年5月17日
    00
  • Spring Data JPA查询方式及方法名查询规则介绍

    Spring Data JPA查询方式及方法名查询规则介绍 Spring Data JPA是Spring Data中用于简化基于JPA开发的数据访问层的框架。它为我们提供了很多简洁、方便的查询方式,本文将介绍Spring Data JPA的查询方式及方法名查询规则。 简单查询 1. 根据ID查询实体 Optional<User> findById…

    Java 2023年6月3日
    00
  • SpringCloud使用Feign实现动态路由操作

    Spring Cloud是一个基于Spring Boot开发的微服务框架,其中Feign作为一个轻量级的HTTP客户端,可以与Eureka、Ribbon等组件实现服务间的通讯,同时,Feign还提供了非常方便的方式进行服务之间的调用。下面,我将详细讲解如何在Spring Cloud中使用Feign进行动态路由操作。 一、添加依赖 在Spring Cloud项…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部