详解用JWT对SpringCloud进行认证和鉴权
什么是JWT
JWT (JSON Web Token) 是一种开放标准 (RFC 7519),它定义了一种简洁的、自包含的方式,用于在不同的系统之间传递安全信息。JWT 通常由 3 部分组成:头部 (header)、载荷 (payload)、签名 (signature)。其中,头部用于描述 JWT 的元数据,载荷是 JWT 中存放有效信息的地方,签名则是用于验证 JWT 真实性的。
JWT在Spring Cloud中的鉴权和认证
在微服务架构中,通常会有多个服务协同工作,因此需要对服务进行鉴权和认证,确保只有经过授权的用户才能访问相应的服务,这时就需要使用 JWT。
Spring Cloud 提供了多种 JWT 鉴权和认证的解决方案,其中最常用的是 Spring Security + JWT。具体实现步骤如下:
- 引入 Spring Security、JWT 相关依赖:
```xml
```
- 配置 Spring Security:
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/login", "/register").permitAll().anyRequest().authenticated().and()
.apply(new JwtConfigurer(jwtTokenProvider));
}
}
```
- 实现 JwtTokenProvider 接口:
```java
public interface JwtTokenProvider {
String createToken(String subject, Map
Claims getClaims(String token);
boolean validateToken(String token);
String getUsername(String token);
List<String> getRoles(String token);
String resolveToken(HttpServletRequest request);
}
```
- 实现 JwtTokenProvider 接口的具体方法:
```java
@Component
public class JwtTokenProviderImpl implements JwtTokenProvider {
private static final Logger logger = LoggerFactory.getLogger(JwtTokenProviderImpl.class);
@Value("${jwt.secret}")
private String secretKey;
@Value("${jwt.token.validity}")
private long validityInMilliseconds;
@Override
public String createToken(String subject, Map<String, Object> claims) {
Date now = new Date();
Date validity = new Date(now.getTime() + validityInMilliseconds);
return Jwts.builder().setSubject(subject).setClaims(claims).setIssuedAt(now).setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, secretKey).compact();
}
@Override
public Claims getClaims(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
}
@Override
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
logger.error("Expired or invalid JWT token: {}", e.getMessage());
}
return false;
}
@Override
public String getUsername(String token) {
return getClaims(token).getSubject();
}
@Override
@SuppressWarnings("unchecked")
public List<String> getRoles(String token) {
return (List<String>) getClaims(token).get("roles");
}
@Override
public String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
```
- 实现 JwtConfigurer:
```java
public class JwtConfigurer extends SecurityConfigurerAdapter
private JwtTokenProvider jwtTokenProvider;
public JwtConfigurer(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
public void configure(HttpSecurity http) throws Exception {
JwtTokenFilter customFilter = new JwtTokenFilter(jwtTokenProvider);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
```
- 实现 JwtTokenFilter:
```java
public class JwtTokenFilter extends OncePerRequestFilter {
private JwtTokenProvider jwtTokenProvider;
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = jwtTokenProvider.resolveToken(request);
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication auth = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(request, response);
}
}
```
示例1:使用Postman测试Spring Cloud中的JWT鉴权和认证
-
启动 Spring Cloud 中的服务,确保服务在本地运行,例如,服务的端口为 8080。
-
使用 Postman 发送 GET 请求时,先不进行 JWT认证。可以通过以下两种方式测试:
-
访问没有配置 JWT 鉴权和认证的接口,例如查询某个用户的基本信息。由于该接口没有访问权限限制,可以正常访问。
-
访问已经配置 JWT 鉴权和认证的接口,例如查询某个订单的详细信息。由于没有 JWT 认证(即没有传入有效的 JWT token),应返回 401 错误码。
-
使用 Postman 发送 POST 请求时,需要进行 JWT 认证。具体步骤如下:
-
以管理员身份登录,获取有效的 JWT token。
-
在 Postman 的请求头中设置 Authorization 字段,其值为 Bearer 后接上述获取的 JWT token。
-
发送包含有效 JWT token 的 POST 请求,例如新增商品信息。由于设置了 JWT 鉴权和认证,只有管理员身份的用户可以访问该接口,其他用户将被拒绝访问。
-
发送包含无效 JWT token 的 POST 请求,例如删除某个商品。由于 JWT 认证不通过,应返回 401 错误码。
示例2:使用Istio的JWT鉴权
-
部署 Istio 服务网格,可以参考官方文档:https://istio.io/latest/docs/setup/install/
-
部署 Spring Cloud 中的服务,并将服务注册到 Istio 中:
-
在 Spring Cloud 的服务配置文件中增加以下配置:
yaml
eureka:
instance:
metadataMap:
istio:
workloadLabels: "app=<your-spring-cloud-app>"其中,
<your-spring-cloud-app>
为 Spring Cloud 服务的名称。 -
在 Istio 的 DestinationRule 配置中增加以下配置:
yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: <your-spring-cloud-app>-destination
spec:
host: <your-spring-cloud-app>
trafficPolicy:
tls:
mode: DISABLE
connectionPool:
http:
http1MaxPendingRequests: 1024
maxRequestsPerConnection: 1024
tcp:
maxConnections: 1024其中,
<your-spring-cloud-app>
为 Spring Cloud 服务的名称。 -
配置 Istio 中的 JWT 鉴权:
-
创建 JWT 证书:
sh
# 生成私钥
openssl genrsa -out ./jwt.key 4096
# 生成公钥
openssl rsa -in ./jwt.key -pubout -out ./jwt.pub其中,
jwt.key
为生成的私钥文件,jwt.pub
为生成的公钥文件。 -
创建 Istio 的 AuthorizationPolicy 配置:
yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: <your-spring-cloud-app>-authorization
spec:
selector:
matchLabels:
app: <your-spring-cloud-app>
version: v1
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["*"]
to:
- operation:
methods: ["*"]其中,
<your-spring-cloud-app>
为 Spring Cloud 服务的名称,v1
为服务的版本。 -
测试 JWT 鉴权:
-
使用 jwt-cli 工具,生成有效的 JWT token:
sh
# 生成包含 username 和 roles 的 JWT token
jwt encode --secret <your-secret-key> --alg HS256 --sub <your-username> --claims roles=<your-roles>其中,
<your-secret-key>
为自定义的密钥,<your-username>
为用户名,<your-roles>
为用户角色信息。 -
在 Postman 的请求头中设置 Authorization 字段,其值为 Bearer 后接上述生成的有效 JWT token。
-
发送 GET 请求,例如查询某个订单的详细信息。由于 JWT 鉴权和认证通过,可以正常访问该接口。
-
发送 GET 请求,例如查询某个用户的基本信息。由于未设置 JWT 鉴权和认证,可以正常访问该接口。
以上就是使用 JWT 对 Spring Cloud 进行认证和鉴权的详细攻略。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解用JWT对SpringCloud进行认证和鉴权 - Python技术站