下面我将为大家详细讲解“Spring Cloud下实现用户鉴权的方案”的完整攻略。本攻略分为以下几个部分:
- Spring Cloud微服务架构
- 鉴权的基本概念
- 用户鉴权的实现方案
- 示例一:使用JWT实现用户鉴权
- 示例二:使用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实现用户鉴权的一般步骤:
- 添加依赖:
<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>
- 实现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;
}
}
- 实现过滤器:
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 {
}
}
- 在配置文件中添加必要的配置:
# JWT配置
jwt:
secret: mySecret
expiration: 3600
header: Authorization
# 忽略鉴权的URL
ignoreUrls:
- /user/login
5. 示例二:使用OAuth2实现用户鉴权
OAuth2是一种标准的开放授权协议。它提供了一种方式,允许第三方应用程序访问用户在其他应用程序上存储的资源。在Spring Cloud下,可以使用Spring Security OAuth2来实现用户鉴权。下面是基于Spring Cloud下使用OAuth2实现用户鉴权的步骤:
- 添加依赖:
<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>
- 配置文件中添加必要配置:
# 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
- 配置过滤器:
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技术站