Spring Cloud下实现用户鉴权的方案

下面我将为大家详细讲解“Spring Cloud下实现用户鉴权的方案”的完整攻略。本攻略分为以下几个部分:

  1. Spring Cloud微服务架构
  2. 鉴权的基本概念
  3. 用户鉴权的实现方案
  4. 示例一:使用JWT实现用户鉴权
  5. 示例二:使用OAuth2实现用户鉴权

1. Spring Cloud微服务架构

Spring Cloud是基于Spring Boot的微服务开发框架。它提供了丰富的库和工具来简化微服务的开发和部署。Spring Cloud包含了一系列的子项目,例如服务发现、负载均衡、配置中心等等。微服务架构通过将应用拆分为小型服务来提高系统的灵活性和可扩展性。

2. 鉴权的基本概念

鉴权是指验证用户的身份是否合法,并决定用户是否有权执行某些操作。在微服务架构中,通常使用token来实现鉴权。当用户登录成功后,系统会生成一个token并返回给用户。用户再次请求时,需要将token携带在请求头中,服务端通过验证token来判断用户的身份是否合法。

3. 用户鉴权的实现方案

在Spring Cloud中,我们可以通过对网关(Gateway)或具体的服务进行配置,来实现用户鉴权。常用的实现方案有以下几种:

  • JWT(Json Web Token)
  • OAuth2
  • Spring Security

在这里我们将重点介绍JWT和OAuth2的实现方案。

4. 示例一:使用JWT实现用户鉴权

JWT是一种轻量级的鉴权方式。它将用户信息编码为一个加密的token,并在每次请求时携带这个token。服务端通过解析token来验证用户的身份。下面是基于Spring Cloud下使用JWT实现用户鉴权的一般步骤:

  1. 添加依赖:
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
  1. 实现JWT工具类:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtTokenUtil {

    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "iat";

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

    /**
     * 根据用户名生成token
     */
    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, username);
        claims.put(CLAIM_KEY_CREATED, new Date());
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 解析token,获取用户名
     */
    public String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否有效
     */
    public boolean validateToken(String token) {
        return !isTokenExpired(token);
    }

    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    private Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    private boolean isTokenExpired(String token) {
        Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    private Date getExpirationDateFromToken(String token) {
        Date expiration;
        try {
            Claims claims = getClaimsFromToken(token);
            expiration = claims.getExpiration();
        } catch (Exception e) {
            expiration = null;
        }
        return expiration;
    }
}
  1. 实现过滤器:
import io.jsonwebtoken.ExpiredJwtException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;

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

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthFilter.class);

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

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private List<String> ignoreUrls;

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

    @Override
    public GatewayFilterFactory<Config> apply(Config config) {
        return (exchange, chain) -> doFilter(exchange, chain, config);
    }

    private Mono<Void> doFilter(ServerWebExchange exchange, GatewayFilterChain chain, Config config) {
        String requestPath = exchange.getRequest().getPath().value();
        for (String ignoreUrl : ignoreUrls) {
            if (requestPath.startsWith(ignoreUrl)) {
                return chain.filter(exchange);
            }
        }
        String token = exchange.getRequest().getHeaders().getFirst(header);
        if (token == null || token.isEmpty()) {
            LOGGER.warn("token is empty");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        try {
            boolean tokenValid = jwtTokenUtil.validateToken(token);
            if (tokenValid) {
                String username = jwtTokenUtil.getUsernameFromToken(token);
                Map<String, Object> attrib = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_ATTRIBUTES);
                Map<String, Object> headers = (Map<String, Object>) attrib.get("headers");
                headers.put("X-Forwarded-User", username);
                return chain.filter(exchange);
            } else {
                LOGGER.warn("token is invalid");
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
        } catch (ExpiredJwtException e) {
            LOGGER.warn("token is expired");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        } catch (Exception e) {
            LOGGER.error("auth error:", e);
            exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            return exchange.getResponse().setComplete();
        }
    }

    @Order(-500)
    public static class Config {
    }
}
  1. 在配置文件中添加必要的配置:
# JWT配置
jwt:
  secret: mySecret
  expiration: 3600
  header: Authorization
# 忽略鉴权的URL
ignoreUrls:
  - /user/login

5. 示例二:使用OAuth2实现用户鉴权

OAuth2是一种标准的开放授权协议。它提供了一种方式,允许第三方应用程序访问用户在其他应用程序上存储的资源。在Spring Cloud下,可以使用Spring Security OAuth2来实现用户鉴权。下面是基于Spring Cloud下使用OAuth2实现用户鉴权的步骤:

  1. 添加依赖:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
  1. 配置文件中添加必要配置:
# auth2配置
security:
  oauth2:
    client:
      client-id: myClientId
      client-secret: myClientSecret
      access-token-uri: http://localhost:8080/oauth/token
      user-authorization-uri: http://localhost:8080/oauth/authorize
      redirect-uri-template: {baseUrl}/login/oauth2/code/{registrationId}
      scope: openid,profile,email
      client-authentication-method: post
  1. 配置过滤器:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;

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

    @Autowired
    private OAuth2AuthorizedClientService clientService;

    @Autowired
    private List<String> ignoreUrls;

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

    @Override
    public GatewayFilterFactory<Config> apply(Config config) {
        return (exchange, chain) -> doFilter(exchange, chain, config);
    }

    private Mono<Void> doFilter(ServerWebExchange exchange, GatewayFilterChain chain, Config config) {
        String requestPath = exchange.getRequest().getPath().value();
        for (String ignoreUrl : ignoreUrls) {
            if (requestPath.startsWith(ignoreUrl)) {
                return chain.filter(exchange);
            }
        }
        OAuth2AuthorizedClient client = getClient(exchange);
        if (client == null) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        OAuth2User user = client.getPrincipal();
        Map<String, Object> attrib = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_ATTRIBUTES);
        Map<String, Object> headers = (Map<String, Object>) attrib.get("headers");
        headers.put("X-Forwarded-User", user.getName());
        return chain.filter(exchange);
    }

    private OAuth2AuthorizedClient getClient(ServerWebExchange exchange) {
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
        if (queryParams.containsKey("code")) {
            String code = queryParams.getFirst("code");
            return clientService.loadAuthorizedClientByAuthorizationCode("myRegistrationId", code);
        }
        return null;
    }

    @Order(-500)
    public static class Config {
    }
}

以上就是使用OAuth2实现用户鉴权的步骤。

希望这篇攻略可以帮助你更好的理解Spring Cloud下实现用户鉴权的方案。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Cloud下实现用户鉴权的方案 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • 详解Spring框架入门

    下面我将为您详细讲解“详解Spring框架入门”的完整攻略。 1. 什么是Spring框架 Spring框架是一个用于Java应用程序开发的开源框架。它最初由Rod Johnson在2002年创建,旨在提供一种允许Java程序员开发企业级应用程序的框架。Spring框架基于Java语言,使用IoC(Inversion of Control)和AOP(Aspe…

    Java 2023年5月20日
    00
  • java中的取整与四舍五入方法实例

    Java中的取整与四舍五入方法实例 在Java中,常用的取整和四舍五入方法是Math.floor、Math.ceil、Math.round,本文将详细介绍这三个方法的用法和示例说明。 Math.floor Math.floor是向下取整,表示得到的最大整数。它的用法为:Math.floor(x),其中x为一个double类型的数。具体实现为删去小数部分,只保…

    Java 2023年5月26日
    00
  • MySQL主从复制的原理图解及Java语言示例使用

    MySQL主从复制是MySQL提供的高可用性和可伸缩性解决方案之一。本文将详细讲解MySQL主从复制的原理,以及如何使用Java语言示例实现MySQL主从复制。 什么是MySQL主从复制 MySQL主从复制是指将一个MySQL数据库实例(称为“主”或“主数据库”)复制到一个或多个MySQL数据库实例(称为“从”或“从数据库”)的过程。主数据库上进行的更改可以…

    Java 2023年6月16日
    00
  • Java拦截器和过滤器的区别分析

    下面我就来详细讲解“Java拦截器和过滤器的区别分析”的完整攻略。 首先,我们需要了解Java中拦截器和过滤器的基本概念以及其作用。拦截器和过滤器都是用于对请求进行拦截和处理的组件。 一、拦截器和过滤器的基本概念 1.1 拦截器 拦截器是在Java中用于拦截请求,其主要作用是拦截请求并对其进行处理,然后将请求转发给下一个处理器。拦截器可以用来做很多事情,比如…

    Java 2023年6月15日
    00
  • Java语言的11大特点(Java初学者必知)

    Java语言的11大特点(Java初学者必知) Java作为一门流行度非常高的编程语言,在软件开发领域拥有着广泛的应用。它具有一些独特的特点,使它成为了开发人员的最爱。下面我们将介绍Java语言的11大特点。 1. 简单 Java语言的语法十分简单,易于学习和理解。它摒弃了其它编程语言中的复杂特性,比如指针和操作符重载,提供了更加简单明了的语法规则。 2. …

    Java 2023年5月23日
    00
  • Springboot整合策略模式详解

    Spring Boot整合策略模式详解 策略模式是一种常用的设计模式,它可以帮助我们在运行时选择不同的算法或行为。在本文中,我们将详细讲解如何在Spring Boot中使用策略模式,并提供两个示例来演示如何使用策略模式。 策略模式简介 策略模式是一种行为型设计模式,它定义了一系列算法或行为,并将它们封装在独立的类中,使得它们可以相互替换。策略模式可以帮助我们…

    Java 2023年5月15日
    00
  • Spring和Hibernate的整合操作示例

    下面是关于Spring和Hibernate整合的完整攻略。 攻略概述 Spring和Hibernate整合的主要目的是为了将Spring的控制反转(IoC)和依赖注入(DI)与Hibernate的ORM框架结合起来,使开发变得更为高效且有组织。通过整合,Spring可以管理Hibernate的Session和事务,并使得对数据库进行操作更为方便。 整合步骤:…

    Java 2023年5月19日
    00
  • Java 集合系列(二)ArrayList详解

    Java 集合系列(二)ArrayList详解 一、ArrayList概述 ArrayList是Java中最常用的集合类之一,其底层是由数组实现的动态数组结构。与数组相比,ArrayList具有容量可动态增加、元素可动态删除、插入,方便灵活,更加适合实际业务需求。 二、ArrayList常用操作 1.创建ArrayList集合 通过无参构造器可以创建一个初始…

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