详解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中Unicode的编码和实现

    浅谈Java中Unicode的编码和实现 什么是Unicode? Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,它对世界上大部分的文字系统进行了编码,以便实现文字在计算机内的处理。Unicode利用一组标准编码,为世界上所有的文字和符号都指定了一个唯一的代码位,用于在计算机中存储、交换和处理。在Java中,char类型采用的编码是…

    Java 2023年5月20日
    00
  • Java顺序表实现图书管理系统

    让我详细讲解一下“Java顺序表实现图书管理系统”的完整攻略。 概述 顺序表是一种简单、易于实现的数据结构,在实现图书管理系统时,可以用来存储图书信息,如书名、作者、出版社、出版日期等。本文将介绍如何使用Java语言实现顺序表来完成一个简单的图书管理系统。 步骤 1.定义Book类 首先,我们需要定义一个Book类来表示图书信息。该类包含以下属性: 书名(S…

    Java 2023年5月30日
    00
  • 剑指Offer之Java算法习题精讲数组与字符串题

    以下是“剑指Offer之Java算法习题精讲数组与字符串题”的完整攻略。 1. 确定题目类型 在学习算法习题时,首先要确定题目类型,以便可以快速地想出解题思路。本篇攻略的主要题目类型为数组与字符串。在处理数组与字符串问题时,可以考虑使用双指针、哈希表和动态规划等常用的技巧。 2. 学习题目解法思路 在确定了题目类型之后,使用双指针、哈希表和动态规划等技巧,根…

    Java 2023年5月19日
    00
  • Java中的多种文件上传方式总结

    下面我将详细讲解“Java中的多种文件上传方式总结”的完整攻略。 Java中的多种文件上传方式总结 背景 在Web应用程序中,常常需要上传文件,例如上传图片、视频、文件等等。Java中有多种文件上传方式,下面将为大家总结这些方式及其优缺点。 方式一:使用Servlet 3.0提供的Part接口进行文件上传 在Servlet 3.0中,新增了Part接口,可以…

    Java 2023年5月20日
    00
  • 转载一个别人收藏的精典网站Ruby,HIBERNATE相关

    关于“转载一个别人收藏的精典网站Ruby,HIBERNATE相关”的完整攻略,我会按照以下步骤进行详细讲解: 1. 确定转载目的 在转载一篇文章之前,我们需要明确自己的转载目的。是为了丰富自己的博客内容,还是为了分享给更多人?这一点很重要,因为它将决定你应该如何进行转载。 2. 征求原作者许可 在转载别人的文章之前,最重要的是要获得原作者的授权,否则可能会引…

    Java 2023年5月20日
    00
  • Spring Boot 底层原理基础深度解析

    Spring Boot 底层原理基础深度解析 Spring Boot 是一款基于 Spring 框架的开发框架,它的出现极大地提高了开发效率。本篇文章将从底层原理入手,对 Spring Boot 的实现机制进行深度解析。 Spring Boot 的核心概念 Spring Boot 的核心概念包括自动装配、起步依赖和 SpringApplication。其中,…

    Java 2023年5月15日
    00
  • Myeclipse怎么更改默认的class模板?

    更改MyEclipse默认的class模板需要经过以下几个步骤: 打开MyEclipse,在顶部菜单栏点击“Window -> Preferences”,打开MyEclipse的偏好设置。 在弹出的“Preferences”对话框中,找到“Java -> Code Style -> Code Templates”选项。点击它,可以看到MyE…

    Java 2023年6月15日
    00
  • Java实现简单的弹球游戏

    Java实现简单的弹球游戏完整攻略 1. 简介 弹球游戏是一种经典的街机游戏,玩家需要控制一个挡板来接住反弹的球。该游戏通常需要使用图形界面来实现,本攻略通过使用Java Swing库来实现一个简单的弹球游戏。 2. 实现步骤 2.1 创建主框架 在Java Swing中,主框架(Frame)用于承载游戏的所有UI组件,我们需要先创建一个主框架。示例代码如下…

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