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日

相关文章

  • 在Java中按值调用和按引用调用

    在Java中,传递参数时有两种方式:按值传递和按引用传递。这两种方式有着不同的使用场景和特点,需要进行深入的探讨。 按值传递 在Java中,按值传递是指将数据(即变量的值)复制一份传递给被调用的方法。修改被传递进方法中的值不会影响调用方法前变量的值。 下面是一个按值传递的例子: public class PassByValueExample { public…

    Java 2023年5月20日
    00
  • SpringBoot项目如何访问jsp页面的示例代码

    下面是关于Spring Boot项目访问jsp页面的攻略及两条示例说明。 一. 配置pom.xml文件 在Spring Boot项目的pom.xml文件中,添加如下依赖: <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>to…

    Java 2023年6月15日
    00
  • 如何使用​win10内置的linux系统启动spring-boot项目

    下面是如何使用Win10内置的Linux系统启动spring-boot项目的完整攻略。 安装WSL WSL(Windows Subsystem for Linux)是Win10内置的Linux子系统,可在其上运行各种Linux发行版。要使用WSL启动spring-boot项目,首先需要安装WSL: 打开”控制面板”,进入”程序与功能”,选择左侧的”启用或关闭…

    Java 2023年5月19日
    00
  • JSP动态网页开发原理详解

    JSP即Java Server Pages,是一种基于Java语言的服务器端动态网页开发技术。使用 JSP 可以轻松开发动态网页,并且对于前端开发人员来说,JSP 的语法也比较友好,易于理解和掌握。下面将从几个方面详细讲解JSP的开发原理。 JSP原理 JSP的原理是将HTML页面和Java代码交织在一起,JSP页面中可以使用HTML标记,在其中使用Java…

    Java 2023年5月19日
    00
  • 详解MyBatis多数据源配置(读写分离)

    下面是详细讲解“详解MyBatis多数据源配置(读写分离)”的完整攻略。 什么是MyBatis多数据源配置? MyBatis多数据源配置指的是在一个项目中同时使用多个数据源,本文重点讲解的是如何实现读写分离的多数据源配置。读写分离是指将数据库中读操作和写操作分别分配到不同的数据库实例上,以达到负载均衡和优化数据库性能的目的。MyBatis是一个优秀的数据持久…

    Java 2023年5月20日
    00
  • 关于logBack配置日志文件及编码配置的问题

    关于logBack配置日志文件及编码配置的完整攻略如下: 1. 导入Logback依赖 首先需要在项目中导入Logback依赖,可以在pom.xml中进行配置: <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic&…

    Java 2023年5月20日
    00
  • java 使用策略模式操作JDBC数据库

    使用策略模式操作JDBC数据库 什么是策略模式 策略模式是一种行为设计模式,它可以让你定义一系列的算法,将这些算法封装起来并且可以相互替换。策略模式让算法的变化独立于使用算法的客户端(调用者)。本质上来讲,策略模式是一种用来管理过多相似类的经典方法,使用策略模式可以避免使用大量的if语句。 策略模式在Java中的应用 在Java中,我们可以使用策略模式对JD…

    Java 2023年6月16日
    00
  • Java多线程执行处理业务时间太久解决方法代码示例

    针对你提出的问题,我会给出一份详细讲解“Java多线程执行处理业务时间太久解决方法代码示例”的完整攻略,过程中会包含以下几个部分的内容: Java多线程执行处理业务时间太久的原因 解决Java多线程执行处理业务时间太久的解决方案 代码示例 为了更好的与你展开对话,接下来我会就每个部分分别进行详细说明。 Java多线程执行处理业务时间太久的原因 在Java多线…

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