详解SpringCloud服务认证(JWT)

详解Spring Cloud服务认证(JWT)

简介

随着微服务架构的广泛应用,越来越多的服务被拆分成多个小的服务来实现业务逻辑。在这些服务之间进行调用时,我们需要确保服务之间的安全性和认证性。JWT(JSON Web Token)是目前流行的一种跨服务认证机制,它基于无状态性的架构,不需要在服务端记录用户状态,能够承载一些声明信息,以相对较为安全的方式在服务之间进行传递。Spring Cloud提供了丰富的功能来支持基于JWT的服务认证机制。

本文将详细讲解Spring Cloud中如何使用JWT来实现服务认证的过程,包括JWT的生成、验证以及在Spring Cloud中的应用。

JWT的生成

首先,我们需要了解JWT的生成机制。一个JWT令牌由三个部分组成:Header、Payload和Signature。Header部分包含了令牌类型和算法类型;Payload部分包含了一些实体的声明(如:用户信息、时间戳等),Payload是JWT的主要内容;Signature部分是对Header和Payload的签名,用于验证Payload的完整性。

在Spring Cloud中,我们可以使用Spring Security来生成JWT令牌。Spring Security中包含了JwtHelper这个类,用于生成、解析、验证JWT令牌。下面是一个生成JWT的示例代码:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;
import java.util.Date;

public class JwtUtil {
    public final static long EXPIRATION_TIME = 60 * 60 * 1000; // 1 hour

    public static String generateToken(User user) {
        String authorities = "";
        Collection<? extends GrantedAuthority> authorityCollection = user.getAuthorities();
        if (authorityCollection != null && !authorityCollection.isEmpty()) {
            for (GrantedAuthority authority : authorityCollection) {
                authorities += authority.getAuthority() + ",";
            }
        }

        return Jwts.builder()
                .setSubject(user.getUsername())
                .claim("authorities", authorities)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, "secret")
                .compact();
    }
}

上述代码中,我们首先定义了一个Token的过期时间,这里设置为1小时。然后,获取用户的权限信息,并将这些权限加入到JWT的Payload中。最后,使用Jwts对象创建一个JWT令牌,并使用HS512算法对Header和Payload进行签名,同时传入一个加密key。

JWT的验证

对于接受到的JWT令牌,我们需要进行验证,以确保Payload中的信息是有效的。Spring Security提供了很多可以设置的配置项,来实现JWT令牌的验证。下面是一个基于Spring Security的JWT验证示例代码:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class JwtAuthenticationFilter {
    private final String HEADER = "Authorization";
    private final String PREFIX = "Bearer ";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        try {
            Authentication authentication = getAuthentication(request);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(request, response);
        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        }
    }

    private Authentication getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(HEADER);
        if (token != null && token.startsWith(PREFIX)) {
            try {
                Claims claims = Jwts.parser()
                        .setSigningKey("secret")
                        .parseClaimsJws(token.replace(PREFIX, ""))
                        .getBody();

                String username = claims.getSubject();
                if (username != null) {
                    List<GrantedAuthority> authorities = Arrays.stream(claims.get("authorities").toString().split(","))
                            .map(SimpleGrantedAuthority::new)
                            .collect(Collectors.toList());

                    return new UsernamePasswordAuthenticationToken(username, null, authorities);
                }
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }
}

上述代码中,我们首先获取请求头中的Authorization,然后验证Authorization的格式是否为"Bearer token"。接着,我们使用Jwts对象解析JWT令牌,并获取用户的信息。最后,使用这些用户信息创建一个UsernamePasswordAuthenticationToken对象,并返回。

Spring Cloud中的应用

经过上述的介绍,我们已经了解了如何生成和验证JWT令牌。在Spring Cloud中,我们需要配置各个服务之间相互通信的JWT认证信息。下面是一个基于Spring Cloud的JWT认证配置示例:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/service1/**").hasRole("ROLE_ADMIN")
                .antMatchers("/service2/**").hasRole("ROLE_USER")
                .antMatchers("/service3/**").permitAll()
                .and()
                .addFilter(new JwtAuthenticationFilter())
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password("{noop}admin")
                .roles("ADMIN")
                .and()
                .withUser("user")
                .password("{noop}user")
                .roles("USER");
    }
}

上述代码中,我们首先使用@EnableWebSecurity注解开启Spring Security的Web安全功能。然后,我们配置了HttpSecurity,限制了各个服务的角色访问权限。接着,我们为HttpSecurity添加了JwtAuthenticationFilter过滤器,用于接受和验证JWT令牌。最后,我们配置了两个用户和角色。

结语

通过本文的介绍,现在你已经可以使用JWT来实现Spring Cloud中的服务认证机制了。在生产环境中,请一定保护好JWT令牌和加密key,以确保服务的安全性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解SpringCloud服务认证(JWT) - Python技术站

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

相关文章

  • java中的三种取整函数总结

    关于Java中三种取整函数的总结,我给出以下详细讲解。 一、背景 在Java编程中,我们有时需要对数字进行取整操作。Java中有三种常用的取整函数:向下取整(floor),四舍五入(round),向上取整(ceil),这些函数都属于Math类。 二、方法说明 下面分别对这三个方法进行详细说明。 1. floor(double a) 该方法是向下取整,表示将参…

    Java 2023年5月26日
    00
  • eclipse下整合springboot和mybatis的方法步骤

    下面是整合Spring Boot和Mybatis的方法步骤: 准备工作 安装Eclipse IDE,确保你已经安装了Eclipse插件“Spring Tools 4”,这个插件可以大大简化整合的过程。 创建一个基于Maven的Spring Boot项目,在pom.xml文件中添加如下依赖项: <dependencies> <!– Spri…

    Java 2023年5月20日
    00
  • Java中的复合数据类型

    下面是Java中的复合数据类型的详细讲解: 什么是复合数据类型 在Java中,复合数据类型是由多个简单数据类型组合而成的数据类型,这些简单数据类型可以是Java内置的基本数据类型或是其他复合数据类型。复合数据类型也可以被称为复杂数据类型或组合数据类型。 在Java中,有以下几种复合数据类型:- 数组(Array)- 类(Class)- 接口(Interfac…

    Java 2023年5月26日
    00
  • JDK14的新特性NullPointerExceptions的使用

    下面是详细讲解“JDK14的新特性NullPointerExceptions的使用”的完整攻略。 什么是NullPointerExceptions NullPointerExceptions 是 Java 程序中最常见的错误之一,它通常会在代码中使用空引用时发生。在 JDK14 中,对于这个问题已经进行了一些新的改进,我们可以更加方便地处理这个问题。 如何使…

    Java 2023年5月27日
    00
  • Java中输入输出方式的简单示例

    Java 是一门广泛应用于开发各种类型应用程序的语言,输入输出是 Java 的重要部分。在 Java 中,有多种输入输出方式,常用的有标准输入、文件输入输出、网络输入输出、控制台输入输出等等。下面就对这些输入输出方式进行一个简单的示例介绍。 标准输入输出示例 在 Java 中,标准输入输出是最简单的一种输入输出方式。标准输出可以用 System.out.pr…

    Java 2023年5月19日
    00
  • java整数(秒数)转换为时分秒格式的示例

    让我来详细讲解一下如何将 Java 中的整数(秒数)转换为时分秒格式。 思路分析 将秒数转换为时分秒格式,其实就是将秒数拆分为小时、分钟、秒三个部分,然后格式化输出。可以使用 Java 中的数学运算和字符串格式化实现。 具体操作如下: 计算出总秒数中包含的小时数、分钟数和秒数; 使用字符串格式化输出结果。 代码实现 下面是整数(秒数)转换为时分秒格式的示例代…

    Java 2023年5月20日
    00
  • 微信小程序实现书架小功能

    下面我将为你详细讲解如何在微信小程序中实现书架小功能。 1. 准备工作 在开始实现之前,你需要安装并配置好微信小程序开发工具,同时了解一些基本的微信小程序开发知识。如果你还没有完成这些准备工作,可参考官方文档进行学习。 2. 创建页面 首先,需要在小程序中创建一个页面来展示书架。在微信小程序开发者工具中,点击新建页面,命名为bookshelf。同时,在根目录…

    Java 2023年5月23日
    00
  • 浅谈servlet中的request与response

    关于“浅谈servlet中的request与response”,下面我来详细讲解一下。 什么是servlet中的request和response 在servlet中,request和response是指HTTP请求和响应中的对象,是Servlet API的一部分。这两个对象扮演了重要的角色,它们是处理HTTP请求和生成HTTP响应的必经之路。 具体而言,re…

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