SpringCloud搭建微服务之Gateway+Jwt实现统一鉴权

这篇具有很好参考价值的文章主要介绍了SpringCloud搭建微服务之Gateway+Jwt实现统一鉴权。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 概述

在微服务项目中,需要对整个微服务系统进行权限校验,通常有两种方案,其一是每个微服务各自鉴权,其二是在网关统一鉴权,第二种方案只需要一次鉴权就行,避免了每个微服务重复鉴权的麻烦,本文以网关统一鉴权为例介绍如何搭建微服务鉴权项目。
本文案例中共有四个微服务模块,服务注册中心、网关服务、鉴权服务和业务提供者
案例中使用组件版本号如下:

组件 版本
JDK 11
SpringBoot 2.7.9
SpringCloud 2021.0.6
Mybatis-Plus 3.5.3.1
jjwt 0.11.5

2. 鉴权微服务

新建一个SpringBoot项目,命名为springcloud-auth-server

2.1. 引入核心依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>${mybatis-plus.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>${jjwt.version}</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>${jjwt.version}</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>${jjwt.version}</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

2.2. 编写JWT业务类

@Service
public class JwtService {

    private static final String SECRET = "JOE38R39GNGRTU49Y534YNIGEYR534YNDEUR7964GEUR735";

    public void validateToken(final String token) {
        Jwts.parserBuilder()
                .setSigningKey(getSignKey())
                .build()
                .parseClaimsJws(token);
    }

    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, username);
    }

    private String createToken(Map<String, Object> claims, String username) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(new Date(Instant.now().toEpochMilli()))
                .setExpiration(new Date(Instant.now().toEpochMilli() + 1000 * 30 * 60))
                .signWith(getSignKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    private Key getSignKey() {
        byte[] keyBytes = Decoders.BASE64.decode(SECRET);
        return Keys.hmacShaKeyFor(keyBytes);
    }
}

2.3. 编写配置类

@Configuration
@EnableWebSecurity
public class AuthConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf()
                .disable()
                .authorizeHttpRequests()
                .antMatchers("/auth/register", "/auth/token", "/auth/validate").permitAll();
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return new CustomUserDetailsService();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService());
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }
}

2.4. 编写Security用户认证

新建CustomUserDetails类实现UserDetails接口

public class CustomUserDetails implements UserDetails {

    private String username;
    private String password;

    public CustomUserDetails(UserCredential userCredential) {
        this.username = userCredential.getUsername();
        this.password = userCredential.getPassword();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

编写CustomUserDetailsService类实现UserDetailsService接口

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private AuthService authService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<UserCredential> credential = authService.findUserByUsername(username);
        return credential.map(CustomUserDetails::new).orElseThrow(() -> new UsernameNotFoundException("user not found"));
    }
}

说明:文中用到的用户认证类UserCredential只有用户名和密码字段,实体类、持久层接口和业务类接口都比较简单,文中就不一一列举

2.5. 编写权限Controller类

@RestController
@RequestMapping(value = "/auth")
public class AuthController {

    @Autowired
    private AuthService authService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private JwtService jwtService;
    @Autowired
    private AuthenticationManager authenticationManager;

    @PostMapping(value = "/register")
    public ResponseEntity createUser(@RequestBody UserCredential credential) {
        credential.setPassword(passwordEncoder.encode(credential.getPassword()));
        authService.save(credential);
        return ResponseEntity.status(HttpStatus.CREATED).build();
    }

    @PostMapping(value = "/token")
    public ResponseEntity<String> generateToken(@RequestBody AuthRequest authRequest) {
        final Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword()));
        if (authenticate.isAuthenticated()) {
            final String token = jwtService.generateToken(authRequest.getUsername());
            return ResponseEntity.status(HttpStatus.OK).body(token);
        } else {
            throw new RuntimeException("invalid access");
        }
    }

    @GetMapping(value = "/validate")
    public ResponseEntity validateToken(@RequestParam String token) {
        jwtService.validateToken(token);
        return ResponseEntity.status(HttpStatus.ACCEPTED).build();
    }
}

3. 网关微服务

新建一个SpringBoot项目,命名为springcloud-gateway

3.1. 引入核心依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>${jjwt.version}</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>${jjwt.version}</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>${jjwt.version}</version>
</dependency>

3.2. 编写权限过滤器类

@Component
public class AuthenticationFilter extends AbstractGatewayFilterFactory<AuthenticationFilter.Config> {

    @Autowired
    private RouteValidator validator;

    public AuthenticationFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            if (validator.isSecured.test(exchange.getRequest())) {
                if (!exchange.getRequest().getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
                    throw new RuntimeException("missing authorization header");
                }
                String authHeader = exchange.getRequest().getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
                if (null != authHeader && authHeader.startsWith("Bearer ")) {
                    authHeader = authHeader.substring(7);
                }
                try {
                    JwtUtil.validateToken(authHeader);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException("un authorized access to application");
                }
            }
            return chain.filter(exchange);
        });
    }

    public static class Config {

    }
}

3.3. 编写application.yml配置

spring:
  application:
    name: CLOUD-GATEWAY
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: provider_routh
          uri: lb://CLOUD-PROVIDER-SERVER
          predicates:
            - Path=/provider/server/**
          filters:
            - AuthenticationFilter
        - id: auth_routh
          uri: lb://CLOUD-AUTH-SERVER
          predicates:
            - Path=/auth/**

4. 测试

依次启动注册中心服务、网关服务、鉴权服务和业务提供服务
postman发起post请求http://localhost:8000/auth/token获取token
spring cloud gateway 权限验证,SpringCloud,spring cloud,微服务,gateway,统一鉴权
postman发起get请求http://localhost:8000/provider/server/info,将上面获取的token携带上,如下配置
spring cloud gateway 权限验证,SpringCloud,spring cloud,微服务,gateway,统一鉴权
Type类型选择No Auth,再次发起请求
spring cloud gateway 权限验证,SpringCloud,spring cloud,微服务,gateway,统一鉴权
查看后台日志会发现是因为没有token
spring cloud gateway 权限验证,SpringCloud,spring cloud,微服务,gateway,统一鉴权
说明:本文只是简单实现了gateway实现统一鉴权功能,有些地方还需要小伙伴自行优化,例如没有token异常提示可以返回给前端文章来源地址https://www.toymoban.com/news/detail-537792.html

到了这里,关于SpringCloud搭建微服务之Gateway+Jwt实现统一鉴权的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Gateway使用JWT实现统一身份认证

    在开发集群式或分布式服务时,鉴权是最重要的一步,为了方便对请求统一鉴权,一般都是会放在网关中进行处理。目前非常流行的一种方案是使用JWT,详细的使用说明,可以找相关的资料查阅,这里先不进行深入的引用了。主要使用它下面的特性: 它的数据使用JSON格式封

    2024年02月12日
    浏览(42)
  • Spring Cloud Gateway + Oauth2 实现统一认证和鉴权!

    micro-oauth2-gateway:网关服务,负责请求转发和鉴权功能,整合Spring Security+Oauth2; micro-oauth2-auth:Oauth2认证服务,负责对登录用户进行认证,整合Spring Security+Oauth2; micro-oauth2-api:受保护的API服务,用户鉴权通过后可以访问该服务,不整合Spring Security+Oauth2。 我们首先来搭建认

    2024年01月16日
    浏览(59)
  • 【实现微服务集成satoken在网关gateway处统一鉴权】

    本文旨在使用开源轻量级 Java 权限认证框架sa-token+springcloud-gateway实现微服务在网关处统一鉴权。sa-token参考地址:https://sa-token.cc/doc.html#/ 项目按照业务分为三个板块,如图: api(也就是微服务中各种api接口,不涉及任何权限相关代码,只提供服务) auth(认证中心,实现登陆逻辑

    2024年02月10日
    浏览(40)
  • 5.微服务项目实战---Gateway--服务网关,实现统一认证、鉴权、监控、路由转发等

    大家都都知道在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用 这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。   这样的架构,会存在着诸多的问题: 客户端多次请求不同的微服务,

    2024年02月16日
    浏览(44)
  • SpringCloud gateway+Spring Security + JWT实现登录和用户权限校验

    原本打算将Security模块与gateway模块分开写的,但想到gateway本来就有过滤的作用 ,于是就把gateway和Security结合在一起了,然后结合JWT令牌对用户身份和权限进行校验。 Spring Cloud的网关与传统的SpringMVC不同,gateway是基于Netty容器,采用的webflux技术,所以gateway模块不能引入spri

    2024年02月03日
    浏览(48)
  • GateWay网关自定义过滤器实现token校验完成统一鉴权

    gateWay---API网关,也可以称为业务网关,主要服务于微服务的; (1)  三大组件 路由(Route)         构建网关的基本模块,由id(唯一标示)、目标URI、一组断言、一组过滤器组成,如果断言为true,则匹配该路由   断言(Predicate)          可以使用它匹配来自HTTP请求的任何

    2024年02月08日
    浏览(45)
  • SpringCloud微服务 【实用篇】| 统一网关Gateway

    目录 一:统一网关Gateway 1. 为什么需要网关 2. gateway快速入门 3. 断言工厂 4. 过滤器工厂 5. 全局过滤器 6. 跨域问题 前面我们已经学习了注册中心Eureka、Nacos和配置管理中心Nacos;但是此时存在很多安全的问题,服务器摆在那里谁都可以进行访问! 网关功能: ① 身份认证和权

    2024年02月04日
    浏览(40)
  • Spring Cloud Gateway集成Swagger实现微服务接口文档统一管理及登录访问

    本文将介绍如何在 Spring Cloud 微服务中使用 Swagger 网关来统一管理所有微服务的接口文档,并通过 Spring Security 实现登录后才能访问 Swagger 文档,以确保接口数据的安全访问。 在开始之前,需要假设你已经完成了 Spring Cloud Gateway 的相关配置,并且已经了解了基本的网关配置知

    2024年02月05日
    浏览(42)
  • 【SpringCloud】11、Spring Cloud Gateway使用Sentinel实现服务限流

    1、关于 Sentinel Sentinel 是阿里巴巴开源的一个流量防卫防护组件,可以为微服务架构提供强大的流量防卫能力,包括流量控制、熔断降级等功能。Spring Cloud Gateway 与 Sentinel 结合,可以实现强大的限流功能。 Sentinel 具有以下特性: 丰富的应用场景:Sentinel 承接了阿里巴巴近

    2024年02月01日
    浏览(54)
  • springboot和flask整合nacos,使用openfeign实现服务调用,使用gateway实现网关的搭建(附带jwt续约的实现)

    插件 版本 jdk 21 springboot 3.0.11 springcloud 2022.0.4 springcloudalibaba 2022.0.0.0 nacos 2.2.3(稳定版) python 3.8 先创建目录,分别创建config,logs,data目录,单独创建一个容器  将配置文件拷贝出来(主要是application.properties和logback.xml) 修改mysql的信息(修改文件application.properties) 再次运行

    2024年02月07日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包