因为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方式的更多相关文章

  1. Spring Cloud OAuth2.0 微服务中配置 Jwt Token 签名/验证

    关于 Jwt Token 的签名与安全性前面已经做了几篇介绍,在 IdentityServer4 中定义了 Jwt Token 与 Reference Token 两种验证方式(https://www ...

  2. SpringCloud(10)使用Spring Cloud OAuth2和JWT保护微服务

    采用Spring Security AOuth2 和 JWT 的方式,避免每次请求都需要远程调度 Uaa 服务.采用Spring Security OAuth2 和 JWT 的方式,Uaa 服务只验证 ...

  3. 使用Spring Cloud OAuth2和JWT保护微服务

    采用Spring Security AOuth2 和 JWT 的方式,避免每次请求都需要远程调度 Uaa 服务.采用Spring Security OAuth2 和 JWT 的方式,Uaa 服务只验证 ...

  4. Spring cloud oauth2.0 access_token 永不失效设置方法

    在AuthorizationServerConfigurerAdapter,重写一个TokenServices,注意这里的@Primary 非常重要,否则会有3个同类型的Bean,无法注入,会抛出以下 ...

  5. 基于spring boot2.0+spring security +oauth2.0+ jwt微服务架构

    github地址:https://github.com/hankuikuide/microservice-spring-security-oauth2 项目介绍 该项目是一个演示项目,主要演示了,基于 ...

  6. 微信授权就是这个原理,Spring Cloud OAuth2 授权码模式

    上一篇文章Spring Cloud OAuth2 实现单点登录介绍了使用 password 模式进行身份认证和单点登录.本篇介绍 Spring Cloud OAuth2 的另外一种授权模式-授权码模式 ...

  7. vue+uni-app商城实战 | 第一篇:【有来小店】微信小程序快速开发接入Spring Cloud OAuth2认证中心完成授权登录

    一. 前言 本篇通过实战来讲述如何使用uni-app快速进行商城微信小程序的开发以及小程序如何接入后台Spring Cloud微服务. 有来商城 youlai-mall 项目是一套全栈商城系统,技术栈 ...

  8. Spring Cloud 2020.0.0正式发布,再见了Netflix

    目录 ✍前言 版本约定 ✍正文 Spring Cloud版本管理 与Spring Boot版本对应关系 当前支持的版本 阻断式升级(不向下兼容) 1.再见了,Netflix Netflix组件替代方案 ...

  9. Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!

    Spring Cloud 2020.0.0 没错,Spring Cloud 2020.0.0 正式发布了: 感谢Java技术栈群友通知,想入群的在公众号Java技术栈后台回复:wx,正在使用 Spri ...

随机推荐

  1. 手动 jq 触发 动态的 layui select change 事件

    var s= $('#province').val(); //先获取   默认选中的第一个 option 的值 ( value)    var select = 'dd[lay-value=' + s ...

  2. Python(一) 快速配置Python编译环境与第一个py文件程序

    1. Python基本语法在此不熬述. 2. 到管网下载Python 3.6.x 版本,与本机匹配的版本,如本机是 win7 64 python-3.6.5-amd64 3. 下载IDE:Python ...

  3. When you received Ubuntu...

    翻译软件 Goldendict 安装命令: sudo apt install goldendict 在 dit -> Dictinoaries -> Websites 中添加有道的链接: ...

  4. CSP-S 2020 题解

    赛后我重拳出击,赛场上我却爆零.哎. 题解本人口胡.有错请各位大佬们指出. A. 儒略日 这题是大型模拟题. 介绍两种写法:一种代码量致死(赛 场 自 闭),一种是非常好写的. 写法 1 我在赛场的思 ...

  5. 解决虚拟机联网问题linux VMware eth0

    虚拟机坏了n多回,真是让我装机装到吐血,经过两天的折腾终于弄明白怎么配置虚拟机的静态ip了. 方法: 1. 将虚拟机关机,--> 打开编辑 ->点击 虚拟网络映射 ->点击 VMne ...

  6. C++ 中使用 PRId64

    同一份代码,Ubuntu 14.04.1 编译没有问题,centos 7 上编译提示错误: error: expected ')' before 'PRId64' 这里两个地址说得很清楚了: http ...

  7. 嵌入式开发笔记——调试组件SEGGER_HardFaultHandle

    一.前言 在使用Cortex-M内核的MCU进行开发时,有时候会因为对内存错误访问等原因造成程序产生异常从而进入HardFaultHandler错误中断.如果程序结构比较复杂,尤其是运行了RTOS时可 ...

  8. python多元回归于调用excel文件

    import xlrd from numpy.linalg import inv import numpy as np data = xlrd.open_workbook(u'C:\\Users\\x ...

  9. iOS常见遍历方法汇总

    一.for循环 NSArray *iosArray = @[@"L", @"O", @"V", @"E", @" ...

  10. MySQL中函数总结

    SQL中提供的函数: version() 查询当前数据库版本 user()   查询当前登录用户 database()    查询当前所在数据库 uuid()   返回uuid的值,分布式情况下数据库 ...