2月5-7日QCon全球软件开发大会携手100+位大咖讲师落定北京,点击查看完整日程>> 了解详情
写点什么

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:003964

评论

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

Flutter版-WanAndroid-App

android 程序员 移动开发

Flutter开发之——事件监听

android 程序员 移动开发

Flutter填坑全面总结(包括Flutter1

android 程序员 移动开发

Flutter开发之——Menu

android 程序员 移动开发

Flutter状态管理--Getx学习2

android 程序员 移动开发

Github TOP100 Android开源

android 程序员 移动开发

Github标星3-2K-2020BATJ数据结构与算法笔试题及其答案吐血整理!

android 程序员 移动开发

Flutter_bloc框架使用笔记,后续估计都不太会用了

android 程序员 移动开发

Flutter动画:用Flutter来实现一个拍手动画

android 程序员 移动开发

Flutter的原理及美团的实践(中)

android 程序员 移动开发

GC 回收机制与分代回收策略

android 程序员 移动开发

Flutter32

android 程序员 移动开发

Flutter教程(二) 了解Dart语言

android 程序员 移动开发

Flutter集成高德定位和地图功能

android 程序员 移动开发

Fragment极度懒加载-+-Layout子线程预加载,奇妙的APP启动速度优化思路

android 程序员 移动开发

Fragment的使用

android 程序员 移动开发

Flutter如何实现下拉刷新和上拉加载更多

android 程序员 移动开发

Flutter绘制-11-旋转小人儿造成的视觉错效

android 程序员 移动开发

Flutter开发之——运行卡在gradle assembleDebug

android 程序员 移动开发

git 补丁 - diff 和 patch 使用详解(1)

android 程序员 移动开发

Flutter-vs-React-Native,谁才是跨平台应用开发的最佳利器?

android 程序员 移动开发

Flutter40

android 程序员 移动开发

Flutter_bloc框架使用笔记,后续估计都不太会用了(1)

android 程序员 移动开发

Flutter与Dart-入门

android 程序员 移动开发

Flutter如何实现下拉刷新和上拉加载更多(1)

android 程序员 移动开发

Flutter实战1 --- 写一个天气查询的APP

android 程序员 移动开发

Flutter开发中的一些Tips(二)

android 程序员 移动开发

Flutter:基于video_player实现视频相关手势控制、全屏播放

android 程序员 移动开发

Flutter40(1)

android 程序员 移动开发

Fragment add与replace的区别(1)(1)

android 程序员 移动开发

Flutter33

android 程序员 移动开发

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