Spring Authorization Server实战

Spring Authorization Server实战

Spring Authorizatin Server

Spring Authorizatin Server是一个框架,它提供了OAuth2.1和OpenID Connect 1.0规范以及其它相关规范的实现,它是基于Spring Security构建的

OAuth2.0协议介绍

OAuth是一个开放标准的授权协议,允许用户授权第三方应用访问其在某个服务提供者上的受保护资源,而无需将其实际的凭证(比如用户和密码)分享给第三方应用。

OAuth2.0协议的流程如下:
在这里插入图片描述
这个流程翻译后如下:

  1. 用户打开客户端后,客户端要求用户给与授权;
  2. 用户同意给客户端授权;
  3. 客户端使用上一步获得授权,向服务器申请令牌;
  4. 授权服务器对客户端认证后,向客户端发放令牌;
  5. 客户端使用令牌,向资源服务器申请获取资源;
  6. 资源服务器确认令牌有效后,向客户端开发资源;

授权流程案例

我们以阿里云盘使用支付宝授权登录来说明这个流程:

  1. 在阿里云盘登录界面,选择支付宝登录;
    在这里插入图片描述

  2. 接着会跳转到支付宝授权的页面,让用户给阿里云盘授权获取用户在支付宝中的信息;
    在这里插入图片描述

  3. 当用户点击同意后,会返回阿里云盘登录界面;

  4. 阿里云盘会使用获得的授权,向支付宝申请token,拿到token后,使用token去支付宝服务器获取用户信息;如果是第一次登录,会根据获取到的信息给用户创建一个阿里云盘的账号,并把支付宝上用户的信息和阿里云盘中创建的账号做一个映射,这样用户下次再登录,直接找到已有的账号登录即可;(这个步骤不需要用户做任何操作,只会在登录界面停留很短的时间,接着就跳转到阿里云盘主界面了)

OAuth2协议的应用场景

OAuth2协议的应用场景非常广泛,只要是涉及到第三方应用程序访问用户数据和资源的场景都可以使用

授权模式

OAuth2有四种授权模式,每种授权模式有不同的应用场景。四种模式如下:

  • 授权码模式:使用最为广泛的模式;比如上面的阿里云盘登录使用的就是授权码模式;
  • 密码模式(Password):密码模式是一种安全级别较低且要求资源拥有者(用户)完全信任服务器的模式。在OAuth2.1中该模式已经被废除,在第三方平台上使用密码模式是一种非常不安全的行为,假设某平台支持QQ登录,如果用户直接使用QQ账号、密码登录,则该平台就获取了用户的QQ账号、密码;

密码模式的流程如下:
在这里插入图片描述

  • 客户端模式(Client Credentials Grant):客户端模式是指客户端以自己的名义进行授权,而不经过用户授权。客户端模式是安全级别最低且要求授权服务器对客户端高度信任的模式。因为客户端向服务器请求认证授权的过程中没有用户的参与,客户端通过提供自己在授权服务器上的信息即可在授权服务器完成认证授权,而客户端获取授权后即可向服务器请求资源。这种模式一般用于对接接口,比如对接北森之类系统的接口;

客户端模式的流程如下:
在这里插入图片描述

  • 令牌刷新模式:如果令牌的有效期到了,如果让客户端重复之前的流程再去获取token,比较麻烦;OAuth2允许用户自动更新令牌。令牌刷新模式是对access_token过期的一种补办操作,OAuth2在给客户端颁发令牌的时候同时给客户端颁发了refresh_token,当access_token过期后,客户端拿refresh_token再去申请新的access_token即可

令牌刷新模式流程如下:
-

OAuth2.1协议

OAuth2.1协议主要是对OAuth2.0的改进,OAuth 2.1去掉了OAuth2.0中的密码模式、简化模式,增加了设备授权码模式,同时也对授权码模式增加了PKCE扩展。
点击查看OAuth2.1的内容

OpenID Connect 1.0协议

OpenID Connect 1.0 是 OAuth 2.0 协议之上的一个简单的身份层。其实就是客户端向认证服务器请求认证授权的时候,多返回一个 id_token,该 id_token 是一串使用 jwt 加密过的字符串。
OpenID Connect 1.0协议详细内容

OAuth实战

授权服务器

引入依赖

    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>3.1.4</spring-boot.version>
    </properties>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
        </dependency>

相关配置


@Configuration
@EnableWebSecurity
public class SecurityConfig {


    /**
     *  Spring Authorization Server 相关配置
     *  主要配置OAuth 2.1和OpenID Connect 1.0
     */
    @Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
            throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                //开启OpenID Connect 1.0(其中oidc为OpenID Connect的缩写)
                .oidc(Customizer.withDefaults());
        http
                //将需要认证的请求,重定向到login进行登录认证。
                .exceptionHandling((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor(
                                new LoginUrlAuthenticationEntryPoint("/login"),
                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                        )
                )
                // 使用jwt处理接收到的access token
                .oauth2ResourceServer((resourceServer) -> resourceServer
                        .jwt(Customizer.withDefaults()));

        return http.build();
    }

    /**
     *  Spring Security 过滤链配置(此处是纯Spring Security相关配置)
     */
    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
            throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        //设置所有请求都需要认证,未认证的请求都被重定向到login页面进行登录
                        .anyRequest().authenticated()
                )
                // 由Spring Security过滤链中UsernamePasswordAuthenticationFilter过滤器拦截处理“login”页面提交的登录信息。
                .formLogin(Customizer.withDefaults());

        return http.build();
    }

    /**
     * 设置用户信息,校验用户名、密码
     */
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails userDetails = User.withDefaultPasswordEncoder()
                .username("test")
                .password("123456")
                .roles("USER")
                .build();
        //基于内存的用户数据校验
        return new InMemoryUserDetailsManager(userDetails);
    }

    /**
     * 注册客户端信息
     *
     * 查询认证服务器信息
     * http://127.0.0.1:9000/.well-known/openid-configuration
     *
     * 获取授权码
     * http://localhost:9000/oauth2/authorize?response_type=code&client_id=oidc-client&scope=profile openid&redirect_uri=http://www.baidu.com
     *
     */
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("oidc-client")
                //{noop}开头,表示“secret”以明文存储
                .clientSecret("{noop}secret")
           .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                // 配置授权码模式,刷新令牌,客户端模式
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                //认证回调地址,接收认证服务器回传的code,需要和客户端配置的一致
                .redirectUri("http://spring-oauth-client:9001/login/oauth2/code/messaging-client-oidc")
                //没有客户端时使用
                .redirectUri("http://www.baidu.com")
                .postLogoutRedirectUri("http://127.0.0.1:8080/")
                .clientName("web-client")
                //设置客户端权限范围
                .scope(OidcScopes.OPENID)
                .scope(OidcScopes.PROFILE)
                //客户端设置用户需要确认授权
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
                .build();

        //配置基于内存的客户端信息
        return new InMemoryRegisteredClientRepository(oidcClient);
    }

    /**
     * 配置 JWK,为JWT(id_token)提供加密密钥,用于加密/解密或签名/验签
     * JWK详细见:https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key-41
     */
    @Bean
    public 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);
    }

    /**
     *  生成RSA密钥对,给上面jwkSource() 方法的提供密钥对
     */
    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;
    }

    /**
     * 配置jwt解析器
     */
    @Bean
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    /**
     * 配置授权服务器请求地址
     */
    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        //什么都不配置,则使用默认地址
        return AuthorizationServerSettings.builder().build();
    }
}

客户端

引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>

yml文件配置

logging:
  level:
    org.springframework.security: trace

spring:
  application:
    name: auth-client
  security:
    oauth2:
      client:
        provider:
          #认证服务器信息
          oauth-server:
            issuer-uri: http://spring-oauth-server:9000   #授权地址
            authorizationUri: ${spring.security.oauth2.client.provider.oauth-server.issuer-uri}/oauth2/authorize  #OAuth2认证服务器的授权端点地址
            tokenUri: ${spring.security.oauth2.client.provider.oauth-server.issuer-uri}/oauth2/token    #令牌获取地址
        registration:
          messaging-client-oidc:
            provider: oauth-server  #认证提供者,标识由哪个认证服务器进行认证,和上面的oauth-server进行关联
            client-name: web-client      #客户端名称
            client-id: oidc-client    #客户端id,从认证平台申请的客户端id
            client-secret: secret      #客户端秘钥
            client-authentication-method: client_secret_basic  #客户端认证方式,除了client_secret_basic还有client_secret_post、client_secret_jwt、private_key_jwt等
            authorization-grant-type: authorization_code     #使用授权码模式获取令牌(token)
            redirect-uri: http://spring-oauth-client:9001/login/oauth2/code/messaging-client-oidc   #回调地址,接收认证服务器回传code的接口地址
            scope:      #OAuth2客户端的权限范围
              - profile  #允许客户端获取用户的个人资料信息
              - openid   #penid 是一个特定的 scope 值,它用于 OpenID Connect 协议中。当客户端应用请求 openid 范围时,它表明应用想要验证用户的身份

资源服务器

引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>

配置

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)
public class ResourceServerConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
                        //所有的访问都需要通过身份认证
                        .anyRequest().authenticated())
                .oauth2ResourceServer((oauth2ResourceServer) -> oauth2ResourceServer
                        .jwt(Customizer.withDefaults()));
        return http.build();
    }

}

配置文件

server:
  port: 9002

logging:
  level:
    org.springframework.security: trace

spring:
  application:
    name: spring-oauth-resource
  security:
    oauth2:
      resource-server:
        jwt:
          issuer-uri: http://spring-oauth-server:9000

测试

直接访问资源服务器中的资源,不代码token
在这里插入图片描述
使用http://spring-oauth-client:9001/token地址,向客户端发起请求,获取token
在这里插入图片描述

携带token访问资源服务器上的资源
在这里插入图片描述

参考

  1. 理解OAuth 2.0
  2. OAuth 2.0
  3. Spring Authorization Server
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Authorization Server是一个基于OAuth 2.0和OpenID Connect(OIDC)协议的身份验证和授权服务器,它提供了一个工具集来构建安全的、可伸缩的和互操作的身份验证和授权解决方案。它可以通过Java Spring框架进行集成,是Java开发人员用于保护Web应用程序的最佳选择。 ### 回答2: Spring Authorization Server是一个基于Spring框架构建的授权服务器。授权服务器是OAuth 2.0授权框架的一部分,用于控制和管理资源的访问权限。通过Spring Authorization Server,用户可以验证和授权第三方应用程序来访问其资源。 Spring Authorization Server 提供了一种安全可靠的方式,用于管理用户的身份验证和授权请求。它使得开发人员能够轻松地构建和定制一个符合其需求的授权服务器。 Spring Authorization Server实现了OAuth 2.0授权框架中的各种授权流程,包括客户端模式、授权码模式、隐式模式和密码模式等。开发者可以根据应用程序的需求来选择和配置适当的授权流程。 Spring Authorization Server还提供了丰富的扩展机制,使得开发者能够对其进行定制和扩展。它与Spring Security和Spring Boot等框架紧密集成,使得开发者能够使用这些强大的工具来增强授权服务器的安全性和功能。 总之,Spring Authorization Server 是一个用于构建和定制授权服务器的框架,通过它可以实现OAuth 2.0授权框架中各种授权流程。它为开发者提供了简单、安全和可扩展的解决方案,使得他们能够轻松地控制和管理应用程序的资源访问权限。 ### 回答3: Spring Authorization Server是一个基于Spring框架开发的认证和授权服务器。它提供了一套全面而灵活的身份验证和授权解决方案,旨在帮助开发者构建安全可靠的应用程序。 首先,Spring Authorization Server支持多种认证方式,包括常见的用户名密码认证、基于OAuth2的授权码认证、密码授权和客户端凭证授权等。开发者可以根据实际需求选择合适的认证方式,确保用户身份验证的安全性。 其次,Spring Authorization Server还支持灵活的授权管理。开发者可以通过定义不同的权限范围和角色来限制用户对资源的访问权限,保护敏感数据的安全。同时,它提供了可扩展的授权策略和自定义认证逻辑的能力,使开发者能够根据具体业务需求进行灵活配置。 另外,Spring Authorization Server支持分布式部署,可以轻松处理高并发的请求。它基于Spring框架的优势,具有良好的扩展性和可维护性,可以与其他Spring生态系统组件无缝集成,如Spring Security、Spring Boot等。 总之,Spring Authorization Server是一个功能强大、安全可靠的认证和授权服务器,为开发者提供了完善的解决方案来保护应用程序的安全性和用户隐私。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值