最新最简洁Spring Cloud Oauth2.0 Jwt 的Security方式
因为Spring Cloud 2020.0.0和Spring Boot2.4.1版本升级比较大,所以把我接入过程中的一些需要注意的地方告诉大家
我使用的版本是Spring boot 2.4.1+Spring Cloud 2020.0.0
我的架构是Gateway做Resource Server,然后服务内部不暴露到外网,微服务之间调用不需要再做验证。
而且为了减少请求Auth Server采用JWT方式
完全使用Spring Security的机制
最新的版本里面取消了org.springframework.cloud:spring-cloud-starter-oauth2
我使用了官方最新推荐集成Oauth2.0
AuthServer:
implementation 'org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure'
implementation 'org.springframework.security:spring-security-oauth2-jose'
Gateway:
implementation 'org.springframework.security:spring-security-config'
implementation 'org.springframework.security:spring-security-oauth2-resource-server'
implementation 'org.springframework.security:spring-security-oauth2-jose'
取消Ribbon之后使用
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer'
下面把关键文件的源码粘贴出来
网关服务器
Gateway:
/**
* 资源服务器配置
* @author Mikey Huang
* @date 2020/12/28
*/
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class ResourceServerConfig {
/**
* 注册安全验证规则
* 配置方式与HttpSecurity基本一致
*/
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { //定义SecurityWebFilterChain对安全进行控制,使用ServerHttpSecurity构造过滤器链;
http.authorizeExchange()
//注意! hasrole里面的值必须和jwt负载的值一致
.pathMatchers("/user/user/login").hasRole("ROLE_ADMIN")
.pathMatchers("/user/user/hello").hasRole("ROLE_USER")
.pathMatchers("/auth/oauth/token", "/auth/oauth/check_token").permitAll()
.anyExchange().authenticated()
.and().csrf().disable();
http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());
return http.build();
}
/**
* 使用ROLE来做权限验证,默认是SCOPE
* @return
*/
@Bean
public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
}
}
server:
port: 8080
spring:
application:
name: gateway
security:
oauth2:
resourceserver:
jwt:
#配置RSA的公钥访问地址
jwk-set-uri: 'http://localhost:8081/.well-known/jwks.json'
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true
routes:
- id: auth
uri: lb://auth
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
- id: user
uri: lb://user
predicates:
- Path=/user/**
filters:
- StripPrefix=1
授权服务器
AuthServer:
/**
* 认证服务器配置
* @author Mikey Huang
* @date 2020/12/28
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final JwtTokenEnhancer jwtTokenEnhancer;
private final ApplicationContext context;
public AuthorizationServerConfig(AuthenticationManager authenticationManager, JwtTokenEnhancer jwtTokenEnhancer,
ApplicationContext context) {
this.authenticationManager = authenticationManager;
this.jwtTokenEnhancer = jwtTokenEnhancer;
this.context = context;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 内存中创建一个客户端
clients.inMemory()
.withClient("client-app")
.secret("123456")
.authorizedGrantTypes("password", "refresh_token")
.scopes("all");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> delegates = new ArrayList<>();
delegates.add(jwtTokenEnhancer);
delegates.add(accessTokenConverter());
// 配置JWT的内容增强器
enhancerChain.setTokenEnhancers(delegates);
endpoints.authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter())
.tokenEnhancer(enhancerChain);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.checkTokenAccess("isAuthenticated()");
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setKeyPair(keyPair());
return jwtAccessTokenConverter;
}
/**
* 通过读取key store的配置构造
* @return
*/
@Bean
public KeyPair keyPair(){
AuthorizationServerProperties properties = authorizationServerProperties();
Resource keyStore = context
.getResource(properties.getJwt().getKeyStore());
char[] keyStorePassword = properties.getJwt().getKeyStorePassword()
.toCharArray();
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(keyStore,
keyStorePassword);
String keyAlias = properties.getJwt().getKeyAlias();
char[] keyPassword = Optional
.ofNullable(properties.getJwt().getKeyPassword())
.map(String::toCharArray).orElse(keyStorePassword);
return keyStoreKeyFactory.getKeyPair(keyAlias, keyPassword);
}
@Bean
public AuthorizationServerProperties authorizationServerProperties() {
return new AuthorizationServerProperties();
}
}
/**
* Spring Security配置
* @author Mikey Huang
* @date 2020/12/28
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**", "/.well-known/jwks.json").permitAll()
.anyRequest().authenticated().and().csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//内存中创建两个用户,两个不同的role用来测试权限
auth.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser("mikey").password("123456").roles("ADMIN")
.and()
.withUser("sirius").password("654321").roles("USER");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// 方便测试,暂时不加密
return NoOpPasswordEncoder.getInstance();
}
}
/**
* @author Mikey Huang
* @date 2020/12/28
*/
@FrameworkEndpoint
public class JwkSetEndpoint {
private final KeyPair keyPair;
@Autowired
public JwkSetEndpoint(KeyPair keyPair) {
this.keyPair = keyPair;
}
@GetMapping("/.well-known/jwks.json")
@ResponseBody
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}
/**
* jwt token增强
* @author Mikey Huang
* @date 2020/12/28
*/
@Component
public class JwtTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
User user = (User) authentication.getPrincipal();
Map<String, Object> info = new HashMap<>();
//存入需要的信息,例如把密码设置到JWT中
info.put("password", user.getPassword());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
return accessToken;
}
}
server:
port: 8081
spring:
application:
name: auth
cloud:
nacos:
discovery:
server-addr: localhost:8848
security:
oauth2:
authorization:
jwt:
key-store: classpath:mikey.jks
key-store-password: 123456
key-alias: mikey
key-password: 123456
测试截图
如果需要测试权限可以用创建的两个账号来分别调用User的两个接口,可以看到ROLE的效果
最新最简洁Spring Cloud Oauth2.0 Jwt 的Security方式的更多相关文章
- Spring Cloud OAuth2.0 微服务中配置 Jwt Token 签名/验证
关于 Jwt Token 的签名与安全性前面已经做了几篇介绍,在 IdentityServer4 中定义了 Jwt Token 与 Reference Token 两种验证方式(https://www ...
- SpringCloud(10)使用Spring Cloud OAuth2和JWT保护微服务
采用Spring Security AOuth2 和 JWT 的方式,避免每次请求都需要远程调度 Uaa 服务.采用Spring Security OAuth2 和 JWT 的方式,Uaa 服务只验证 ...
- 使用Spring Cloud OAuth2和JWT保护微服务
采用Spring Security AOuth2 和 JWT 的方式,避免每次请求都需要远程调度 Uaa 服务.采用Spring Security OAuth2 和 JWT 的方式,Uaa 服务只验证 ...
- Spring cloud oauth2.0 access_token 永不失效设置方法
在AuthorizationServerConfigurerAdapter,重写一个TokenServices,注意这里的@Primary 非常重要,否则会有3个同类型的Bean,无法注入,会抛出以下 ...
- 基于spring boot2.0+spring security +oauth2.0+ jwt微服务架构
github地址:https://github.com/hankuikuide/microservice-spring-security-oauth2 项目介绍 该项目是一个演示项目,主要演示了,基于 ...
- 微信授权就是这个原理,Spring Cloud OAuth2 授权码模式
上一篇文章Spring Cloud OAuth2 实现单点登录介绍了使用 password 模式进行身份认证和单点登录.本篇介绍 Spring Cloud OAuth2 的另外一种授权模式-授权码模式 ...
- vue+uni-app商城实战 | 第一篇:【有来小店】微信小程序快速开发接入Spring Cloud OAuth2认证中心完成授权登录
一. 前言 本篇通过实战来讲述如何使用uni-app快速进行商城微信小程序的开发以及小程序如何接入后台Spring Cloud微服务. 有来商城 youlai-mall 项目是一套全栈商城系统,技术栈 ...
- Spring Cloud 2020.0.0正式发布,再见了Netflix
目录 ✍前言 版本约定 ✍正文 Spring Cloud版本管理 与Spring Boot版本对应关系 当前支持的版本 阻断式升级(不向下兼容) 1.再见了,Netflix Netflix组件替代方案 ...
- Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!
Spring Cloud 2020.0.0 没错,Spring Cloud 2020.0.0 正式发布了: 感谢Java技术栈群友通知,想入群的在公众号Java技术栈后台回复:wx,正在使用 Spri ...
随机推荐
- C# 9.0新特性详解系列之五:记录(record)和with表达式
1 背景与动机 传统面向对象编程的核心思想是一个对象有着唯一标识,表现为对象引用,封装着随时可变的属性状态,如果你改变了一个属性的状态,这个对象还是原来那个对象,就是对象引用没有因为状态的改变而改变, ...
- AcWing 232. 守卫者的挑战
题目链接 大型补档计划. 比较显然的dp 设 \(f[i][j][k]\) 为前 \(i\) 次,擂台上了 \(j\) 次,空闲容量(背包 - 使用的)为 \(k\) 的概率. 不上擂台的转移:\(f ...
- hadoop技术产生
一.为什么有大数据 我的理解是: 1)数据量达到了传统数据库的瓶颈 2)数据量的激增 3)硬件成本的降低 [ 技术水平的上升 ] 4)想通过大量的数据发现潜在的商业价值 二.什么是大数据 大数据指的是 ...
- Nginx安装配置教程
转自https://www.cnblogs.com/zhouxinfei/p/7862285.html nginx概述 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是 ...
- STL—— 容器(vector)的内存分配,声明时的普通构造&带参构造
vector 的几种带参构造 & 初始化与内存分配: 1. 普通的带参构造: vector 的相关对象可以在声明时通过 vector 的带参构造函数进行内存分配,如下: 1 #include ...
- proxySQL with MGR
环境信息 hostname IP port role comm ms81 192.168.188.81 3399 master ms82 192.168.188.82 3399 slave ms83 ...
- 一文带你彻底了解大数据处理引擎Flink内存管理
摘要: Flink是jvm之上的大数据处理引擎. Flink是jvm之上的大数据处理引擎,jvm存在java对象存储密度低.full gc时消耗性能,gc存在stw的问题,同时omm时会影响稳定性.同 ...
- 关于golang的time包总结
目录 前言 time包详解 总结 前言 各种编程语言都少不了与时间有关的操作,因为很多判断都是基于时间,因此正确和方便的使用时间库就很重要额. golang提供了import "time&q ...
- Java内存模型(MESI、内存屏障、volatile和锁及final内存语义)
JMM (Java内存模型) Java线程的实现 实现线程主要有三种方式,Java线程从JDK1.3后采用第一种方式实现: 使用内核线程实现(1:1实现) 使用用户线程实现(1:N实现) 使用用户线程 ...
- Spark性能调优篇一之任务提交参数调整
问题一:有哪些资源可以分配给spark作业使用? 答案:executor个数,cpu per exector(每个executor可使用的CPU个数),memory per exector(每个exe ...