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

yizhihongxing

详解用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日

相关文章

  • shiro会话管理示例代码

    Shiro 是一个非常流行的 Java 安全框架,在 web 开发中用于管理用户权限、会话管理等功能。对于 Shiro 的会话管理功能,我们可以通过在项目中使用 Shiro 自带的 Session Management 模块来实现,下面是 Shiro 会话管理示例代码的完整攻略。 一、Shiro 会话管理基础 Shiro 会话管理的基础是 Session 接…

    Java 2023年6月15日
    00
  • JSP 自定义标签实现数据字典的实例

    下面是“JSP 自定义标签实现数据字典的实例”的完整攻略。 什么是 JSP 自定义标签? JSP 自定义标签是 JSP 技术中的一种扩展机制,它可以让开发者自定义标签和标签库,以此来方便页面的开发和维护。通过自定义标签,我们可以把一些常规的代码片段独立出来,以标签的形式提供给页面的其他部分使用,这样可以极大地减少了开发重复代码的时间和精力。 数据字典是什么?…

    Java 2023年6月15日
    00
  • java事务的概念浅析

    接下来我将详细讲解“Java事务的概念浅析”的完整攻略。 Java事务的概念浅析 什么是事务 在计算机领域,事务是指一组对系统中数据的访问和更新操作,这组操作要么全都执行成功,要么全都不执行,保证了数据的一致性。事务是一种能够保证数据在一些列操作中的完整性和一致性的数据处理方式。 事务的ACID属性 在数据库中,事务必须同时具备ACID四个属性: 原子性(A…

    Java 2023年5月20日
    00
  • Java访问者设计模式详细讲解

    Java访问者设计模式详细讲解 什么是访问者设计模式? 访问者设计模式是一种行为型设计模式,它允许你将对象元素操作与其所在的对象分离开来,并将其封装在另一个对象中。通过这种方式,我们可以在不改变被访问对象的类的前提下,增加新的功能操作。访问者模式在实际应用中非常常见,例如在编译器中,AST(抽象语法树)节点经常会被访问者模式处理。 访问者设计模式的结构 Vi…

    Java 2023年5月26日
    00
  • 关于在IDEA中SpringBoot项目中activiti工作流的使用详解

    关于在IDEA中SpringBoot项目中activiti工作流的使用详解,我将按照以下步骤给出完整攻略: 1. 导入activiti依赖 在SpringBoot项目中使用activiti需要导入相应的Maven依赖。可以在pom.xml文件中添加如下依赖: <dependency> <groupId>org.activiti<…

    Java 2023年6月16日
    00
  • Spring框架七大模块简单介绍

    下面是关于“Spring框架七大模块简单介绍”的完整攻略,包含两个示例说明。 Spring框架七大模块简单介绍 Spring框架是一个开源的Java应用程序框架,它提供了一系列的模块来帮助开发者构建企业级应程序。Spring框架的七大模块分别是:核心容器、数据访问/集成、Web、AOP、消息、测试和Instrumentation。本文将对这七大模块进行简单介…

    Java 2023年5月17日
    00
  • 浅析Java中print、printf、println的区别

    浅析Java中print、printf、println的区别 概述 在Java编程中,我们经常需要在程序中输出信息。而输出信息的方式,主要有三种:print、printf、println。这三种方式虽然非常相似,但是却有着不同的用途和输出效果。本文将详细分析它们之间的区别。 print print是最常用的输出语句之一,用于输出字符串和变量的值。它的使用语法…

    Java 2023年5月26日
    00
  • Springboot集成Kafka进行批量消费及踩坑点

    下面我来详细讲解“Springboot集成Kafka进行批量消费及踩坑点”的完整攻略。 一、前言 Kafka是一款分布式消息队列系统,由Apache在2011年引入,其主要包括了生产者、消费者等API,用于实现消息的发送和接收等操作。而Springboot则是目前流行的一种开发框架,它可以简化Java应用的开发过程。本文将探讨如何在Springboot中集成…

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