写点什么

Spring Authorization Server 1.0 提供了 OAuth 2.1 和 OpenID Connect 1.0 实现

  • 2023-01-18
    北京
  • 本文字数:3400 字

    阅读完需:约 11 分钟

Spring Authorization Server 1.0提供了OAuth 2.1和OpenID Connect 1.0实现

在向 Java 社区推出两年半之后,VMWare发布了 Spring Authorization Server 1.0。 Spring Authorization Server项目构建在Spring Security之上,支持创建OpenID Connect 1.0 Identity Provider 和OAuth 2.1 Authorization Server。该项目取代了业已不再维护的Spring Security OAuth项目。


Spring Authorization Server 也基于Spring Framework 6.0,需要使用 Java 17 作为最低版本。该项目支持特征列表中描述的 Authorization Grants、Token Format、Client Authentication 和 Protocol Endpoints。


有个示例应用阐述了使用Spring Initializr创建 Spring Boot 应用的基本配置。该示例应用是基于 REST 的,需要在**pom.xml**文件中包含_spring-boot-starter-web_依赖:


dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency>
复制代码


为了阐述登录功能,请考虑如下创建 REST 端点的样例:


@RestControllerpublic class TimeController {
@GetMapping("/time") public String retrieveTime() { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); LocalTime localTime = LocalTime.now(); return dateTimeFormatter.format(localTime); }}
复制代码


一个基础的 Spring Boot 应用类用来启动应用与前文创建的 REST 端点:


@SpringBootApplicationpublic class TimeApplication {
public static void main(String[] args) { SpringApplication.run(TimeApplication.class, args); }}
复制代码


在启动应用之后,打开http://localhost:8080/time URL,将会显示当前时间:


21:00:34
复制代码


现在,我们添加 Spring Authorization Server 依赖:


<dependency>    <groupId>org.springframework.security</groupId>    <artifactId>spring-security-oauth2-authorization-server</artifactId>    <version>1.0.0</version></dependency>
复制代码


当再次启动应用后,日志中会打印出密码,例如:


Using generated security password: d73d5904-25a1-44ed-91e1-a32c4c5aedb8
复制代码


现在,当访问http://localhost:8080/time时,请求会重定向到http://localhost:8080/login,并展示如下所示的页面:



我们使用默认的用户名_user_以及打印出的密码登录之后,请求会被重定向到http://localhost:8080/time?continue,并再次显示当前时间。


“开发第一个样例”文档详细介绍了 Spring Authorization Server 需要的几个**@Bean组件,它们应该定义在带有@Configuration**注解的类中。第一个 bean 用来定义 OAuth2 Protocol Endpoint


@Bean@Order(1)public SecurityFilterChain protocolFilterChain(HttpSecurity http)    throws Exception {    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);    http        .exceptionHandling((exceptions) -> exceptions        .authenticationEntryPoint(            new LoginUrlAuthenticationEntryPoint("/login"))        )        .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)        .getConfigurer(OAuth2AuthorizationServerConfigurer.class)        .oidc(Customizer.withDefaults());
return http.build();}
复制代码


第二个 bean 用来定义 Spring Security Authentication


@Bean@Order(2)public SecurityFilterChain authenticationFilterChain(HttpSecurity http) throws Exception {    http    .authorizeHttpRequests((authorize) -> authorize        .anyRequest().authenticated()    )    .formLogin(Customizer.withDefaults());
return http.build();}
复制代码


在真正的产品中,我们应该使用合理的方案来存储用户,但是在这个简单的样例中,用户_james_和密码_gosling_存储在了内存中:


@Beanpublic UserDetailsService userDetailsService() {    UserDetails userDetails = User.withDefaultPasswordEncoder()        .username("james")        .password("gosling")        .roles("FOUNDER")        .build();
return new InMemoryUserDetailsManager(userDetails);}
复制代码


新的客户端使用**RegisteredClientRepository**注册在了内存中:


@Beanpublic RegisteredClientRepository registeredClientRepository() {    RegisteredClient registeredClient =                    RegisteredClient.withId(UUID.randomUUID().toString())        .clientId("id")        .clientSecret("secret")        .clientAuthenticationMethod(            ClientAuthenticationMethod.CLIENT_SECRET_BASIC)        .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)        .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)        .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)        .redirectUri(          "http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")        .redirectUri("http://127.0.0.1:8080/authorized")        .scope(OidcScopes.OPENID)        .scope(OidcScopes.PROFILE)        .scope("message.read")        .scope("message.write")        .clientSettings(            ClientSettings.builder()            .requireAuthorizationConsent(true).build())        .build();
return new InMemoryRegisteredClientRepository(registeredClient);}
复制代码


访问令牌会使用如下的 bean 进行签名,它会使用**com.nimbusds.jose.jwk.RSAKey,而不是java.security.interfaces.RSAKey**:


@Beanpublic JWKSource<SecurityContext> jwkSource() {    KeyPair keyPair = generateRsaKey();    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();    RSAKey rsaKey = new RSAKey.Builder(publicKey)        .privateKey(privateKey)        .keyID(UUID.randomUUID().toString())        .build();    JWKSet jwkSet = new JWKSet(rsaKey);    return new ImmutableJWKSet<>(jwkSet);}
private static KeyPair generateRsaKey() { KeyPair keyPair; try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); keyPair = keyPairGenerator.generateKeyPair(); } catch (Exception ex) { throw new IllegalStateException(ex); } return keyPair;}
复制代码


JwtDecoder会用来解码已签名的访问令牌,它会使用com.nimbusds.jose.proc.SecurityContext,而不是**org.springframework.security.core.context.SecurityContext**:


@Beanpublic JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {    return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);}
复制代码


最后,**AuthorizationServerSettings**会用来配置 OAuth2 认证服务器:


@Beanpublic AuthorizationServerSettings authorizationServerSettings() {    return AuthorizationServerSettings.builder().build();}
复制代码


现在,当浏览http://localhost:8080/time时,可以使用用户名_james_和密码_gosling_来查看当前的时间。在遵循这些步骤后,该应用可以扩展为使用各种 OAuth2 和 OpenID Connect 1.0 功能,如令牌。


有多个视频对 Spring Authorization Server 进行了详细解释,例如 Spring Security 团队的核心提交者Joe Grandja在旧金山 JUG 上做了Spring Authorization Server入门的演讲,Spring Security in Action的作者Laurentiu Spilca在 Spring I/O 上介绍了如何使用Spring Security实现OAuth 2认证服务器


该项目是基于VMware Tanzu开源软件支持策略发布的,这意味着主要版本的支持时间长达三年。另外,VMware 还提供 24/7 的商业支持


更多信息可以参考入门指南参考文档和 GitHub 上的示例


原文链接:

Spring Authorization Server 1.0 Provides Oauth 2.1 and OpenID Connect 1.0 Implementations


相关阅读:

一文看懂OAuth 2.0 (附实践案例)

OAuth 2.0与OpenID Connect协议的完整指南

2023-01-18 08:007519

评论

发布
暂无评论
发现更多内容

浅谈加密算法 aes

奋飞安全

android 安全

关于数据仓库架构及各组件方案选型

五分钟学大数据

数据仓库 4月月更

王者荣耀商城异地多活架构设计

AragornYang

架构训练营 架构实战营

[Day8]-[动态规划] 最长公共子序列

方勇(gopher)

LeetCode 动态规划 数据结构与算法、

声网的混沌工程实践

声网

测试 混沌工程 质量保障 Dev for Dev

数据库原理知识及SQL语言知识拓展

王小王-123

MySQL 数据库 MySQL 数据库 4月月更

模块七作业

blazar

「架构实战营」

读《A Philosophy of Software Design》——(9)

术子米德

架构师成长笔记

读《A Philosophy of Software Design》——(11)

术子米德

架构师成长笔记

Tapdata PDK 生态共建计划启动!Doris、OceanBase、PolarDB、SequoiaDB 等十余家厂商首批加入

tapdata

数据库 实时数据

老项目改造返回值规范化

Rubble

4月日更

架构训练营 模块七

Geek_16d2b8

架构训练营 模块七

众安保险 x StarRocks | 全新实时分析能力开启数字化经营新局面

StarRocks

数据库 StarRocks

王者荣耀商城异地多活架构设计

李大虾

#架构实战营 「架构实战营」

每个互联网人才都应该知道的SQL注入!

喀拉峻

网络安全 安全 渗透测试 SQL注入

读《A Philosophy of Software Design》——(8)

术子米德

架构师成长笔记

云原生小课堂|高性能、高可用、可扩展的MySQL集群如何组建?

York

云原生 MySQL 高可用 MySQL 数据库

SpringBoot接入轻量级分布式日志框架(GrayLog)

Java工程师

Java spring 分布式 springboot 组件

现代间谍技术的演变:从“王牌特工”到“行走的50w”

脑极体

模块7作业

Mr小公熊

不想被开巨额罚单?银行需筑起数据安全“护城河”

WorkPlus

洞见科技深度参编的央行金科联盟「多方安全计算」及「联邦学习」金融应用研究报告正式发布

洞见科技

金融科技 隐私计算 金融创新

那些年我们一起优化的SQL

Java工程师

Java sql 程序员 索引 MySQL 数据库

一文让你深度了解Linux内核架构和工作原理

Linux爱好者

内存管理 Linux内核 进程管理 驱动开发 嵌入式开发

读《A Philosophy of Software Design》——(10)

术子米德

架构师成长笔记

Redis+Caffeine两级缓存,让访问速度纵享丝滑

Java工程师

Java 数据库 redis 架构 高性能

区块链溯源!“有机”食品也要“有迹可循”

旺链科技

区块链 产业区块链 食品追溯

适合 Kubernetes 初学者的一些实战练习 (五)

Jerry Wang

postgresql Kubernetes Cloud Native statefulset 4月月更

美国区块链公司Espresso Systems因涉嫌知识产权盗窃被起诉

石头财经

如何编写一个Linux内核模块,这次手把手教你

Linux爱好者

内存管理 Linux内核 进程管理 嵌入式开发 设备驱动

模块七

Leo

架构实战营

Spring Authorization Server 1.0提供了OAuth 2.1和OpenID Connect 1.0实现_语言 & 开发_Johan Janssen_InfoQ精选文章