前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Oauth 2.0 详解

Oauth 2.0 详解

作者头像
BUG弄潮儿
发布2023-02-24 15:09:32
1.7K0
发布2023-02-24 15:09:32
举报
文章被收录于专栏:JAVA乐园

1. Oauth2简介

简介

  • 第三方认证技术方案最主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要 遵循一定的接口协议。
  • OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。同时,任何第三方都可以 使用OAUTH认证服务,任何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。
  • 业界提供了OAUTH的多种实现如PHP、JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的 时间,因而OAUTH是简易的。
  • 互联网很多服务如Open API,很多大公司如Google,Yahoo, Microsoft等都提供了OAUTH认证服务,这些都足以说明OAUTH标准逐渐成为开放资源授权的标准。
  • Oauth协议目前发展到2.0版本,1.0版本过于复杂,2.0版本已得到广泛应用。

参考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin

Oauth 协议:https://tools.ietf.org/html/rfc6749

实例分析:

下边分析一个Oauth2认证的例子,网站使用微信认证的过程:

  1. 点击“微信”出现一个二维码,此时用户扫描二维码,开始给网站授权,用户是自己在微信信息的资源拥有者
  1. 资源拥有者同意给客户端授权
    1. 资源拥有者扫描二维码表示资源拥有者同意给客户端授权,微信会对资源拥有者的身份进行验证,
    2. 验 证通过后,微信会询问用户是否给授权网站访问自己的微信数据,用户点击“确认登录”表示同意授权, 微信认证服务器会颁发一个授权码,并重定向到网站。
  2. 客户端获取到授权码,请求认证服务器申请令牌
    • 此过程用户看不到,客户端应用程序请求认证服务器,请求携带授权码。
  3. 认证服务器向客户端响应令牌 --不可见
    • 认证服务器验证了客户端请求的授权码,如果合法则给客户端颁发令牌,令牌是客户端访问资源的通行证。此交互过程用户看不到,当客户端拿到令牌后,用户在网站看到已经登录成功。
  4. 客户端请求资源服务器的资源
    • 客户端携带令牌访问资源服务器的资源。
    • 网站携带令牌请求访问微信服务器获取用户的基本信息。
  5. 资源服务器返回受保护资源
    • 资源服务器校验令牌的合法性,如果合法则向用户响应资源信息内容。

注意:资源服务器和认证服务器可以是一个服务也可以分开的服务,如果是分开的服务资源服务器通常 要请求认证服务器来校验令牌的合法性。

Oauth2.0认证流程

引自Oauth2.0协议rfc6749 https://tools.ietf.org/html/rfc6749

角色
客户端
  • 本身不存储资源,需要通过资源拥有者的授权去请求资源服务器的资源,
  • 比如:Android客户端、Web 客户端(浏览器端)、微信客户端等。
资源拥有者
  • 通常为用户,也可以是应用程序,即该资源的拥有者。
授权服务器
  • (也称认证服务器) 用来对资源拥有的身份进行认证、对访问资源进行授权。
  • 客户端要想访问资源需要通过认证服务器由资 源拥有者授权后方可访问。
资源服务器
  • 存储资源的服务器,
  • 比如,网站用户管理服务器存储了网站用户信息,网站相册服务器存储了用户的相 册信息,微信的资源服务存储了微信的用户信息等。
  • 客户端最终访问资源服务器获取资源信息。
常用术语
1、客户凭证(client Credentials) :客户端的clientId和密码用于认证客户
2、令牌(tokens) :授权服务器在接收到客户请求后,颁发的访问令牌
3、作用域(scopes) :客户请求访问令牌时,由资源拥有者额外指定的细分权限(permission)
令牌类型
1、授权码 :仅用于授权码授权类型,用于交换获取访问令牌和刷新令牌
2、访问令牌 :用于代表一个用户或服务直接去访问受保护的资源
3、刷新令牌 :用于去授权服务器获取一个刷新访问令牌
4、BearerToken :不管谁拿到Token都可以访问资源,类似现金
5、Proof of Possession(PoP) Token :可以校验client是否对Token有明确的拥有权
优缺点:
优点:
  • 更安全,客户端不接触用户密码,服务器端更易集中保护
  • 广泛传播并被持续采用
  • 短寿命和封装的token
  • 资源服务器和授权服务器解耦
  • 集中式授权,简化客户端
  • HTTP/JSON友好,易于请求和传递token
  • 考虑多种客户端架构场景
  • 客户可以具有不同的信任级别
缺点:
  • 协议框架太宽泛,造成各种实现的兼容性和互操作性差
  • 不是一个认证协议,本身并不能告诉你任何用户信息。

2.授权模式(常用)

1、授权码模式(Authorization Code)
  • USER-AGENT:浏览器
2、简化授权模式(Implicit)
  • 提前获取访问令牌,但因为在Fragment中无法访问;
  • 通过脚本命令生成
3、密码模式(Resource Owner PasswordCredentials)
  • 简化
4、客户端模式(Client Credentials)
5、刷新令牌
  • 访问令牌过期后不用再重新走一遍流程,可通过刷新令牌从授权服务器重新获取访问令牌

3.Spring Security Oauth2介绍

推荐大神博客:OAuth2.0 说明

代码语言:javascript
复制
https://ruanyifeng.com/
基本介绍

根据我们之前的学习, OAuth是一个开放的授权标准,而Spring Security Oauth2是对OAuth2协议的一种实现框架。下面我们来搭建自己的Spring Security OAuth2的服务框架。

OAuth2的服务提供方包含两个服务,即授权服务(Authorization Server,也叫 做认证服务)和资源服务(Resource Server),使用Spring Security OAuth2的时 候,可以选择在同一个应用中来实现这两个服务,也可以拆分成多个应用来实现同 一组授权服务。

授权服务(Authorization Server)应包含对接入端以及登入用户的合法性进行验 证并颁发token等功能,对令牌的请求断点由Spring MVC控制器进行实现,下面是 配置一个认证服务必须的endpoints:

  • AuthorizationEndpoint服务于认证请求。默认URL:/oauth/authorize
  • TokenEndpoint服务于访问令牌的请求。默认URL:/oauth/token
  • OAuth2AuthenticationProcessingFilter 用来对请求给出的身份令牌进行解析鉴权。

4.Spring security授权服务配置

这一阶段的目的是配置出给客户颁发access_token的服务。这一步主要在授权服务模快中完成

4.1创建配置类

首先,在启动类或者任意一个@Configuration声明的启动类中打开@EnableAuthorizationServer

注释,这个注解是Spring Security打开OAuth认证服务的基础注解。

然后创建配置类继承AuthorizationServerConfigurerAdapter。之前我们配置Spring Security时,利用了WebSecurityConfigurerAdapter注入一个配置对象来完成对基础认证授权功能的配置。在使用OAuth2时,Spring Security也提供了一个类似的适配器来帮助我们完成配置。

代码语言:javascript
复制
package com.tuling.security.distributed.uaa.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;

@Configuration
public class MyAuthorizationConfig extends AuthorizationServerConfigurerAdapter  {

 
}

AuthorizationServerConfigurerAdapter要求配置以下几个类,这几个类是由Spring创建的独立的配置对象,它们会被Spring传入AuthorizationServerConfigurer中进行配置。

代码语言:javascript
复制
public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer {
   public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {}
   public void configure(ClientDetailsServiceConfigurer clients) throws Exception {}
   public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {}
}

这三个配置也是整个授权认证服务中最核心的配置。

  • ClientDetailsServiceConfigurer:用来配置客户端详情服务(ClientDetailsService),客户端详情信息在这里进行初始化,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息。
  • AuthorizationServerEndpointsConfifigurer:用来配置令牌(token)的访问端点和令牌服务(tokenservices)。
  • AuthorizationServerSecurityConfifigurer:用来配置令牌端点的安全约束.
4.2配置客户端详细信息

ClientDetailsServiceConfigurer能够使用内存或者JDBC来实现客户端详情服务(ClientDetailsService),ClientDetailsService负责查找ClientDetails,一个ClientDetails代表一个需要接入的第三方应用,例如我们上面提到的OAuth流程中的百度。ClientDetails中有几个重要的属性如下:

  • clientId: 用来标识客户的ID。必须。
  • secret: 客户端安全码,如果有的话。在微信登录中就是必须的。
  • scope:用来限制客户端的访问范围,如果是空(默认)的话,那么客户端拥有全部的访问范围。
  • authrizedGrantTypes:此客户端可以使用的授权类型,默认为空。在微信登录中,只支持authorization_code这一种。
  • authorities:此客户端可以使用的权限(基于Spring Security authorities)
  • redirectUris:回调地址。授权服务会往该回调地址推送此客户端相关的信息。

Client Details客户端详情,能够在应用程序运行的时候进行更新,可以通过访问底层的存储服务(例如访问mysql,就提供了JdbcClientDetailsService)或者通过自己实现ClientRegisterationService接口(同时也可以实现ClientDetailsService接口)来进行定制。

示例中我们暂时使用内存方式存储客户端详情信息,配置如下:

代码语言:javascript
复制
 @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //内存配置的方式配置用户信息
        clients.inMemory()//内存方式
                .withClient("c1") //client_id
                .secret(new BCryptPasswordEncoder().encode("secret"))//客户端秘钥
                .resourceIds("order")//客户端拥有的资源列表
                .authorizedGrantTypes("authorization_code",
                        "password", "client_credentials", "implicit", "refresh_token")//该client允许的授权类型
                .scopes("all")//允许的授权范围
                .autoApprove(false)//跳转到授权页面
                .redirectUris("http://www.baidu.com");//回调地址
//                .and() //继续注册其他客户端
//                .withClient()
//                ...
//   加载自定义的客户端管理服务 //   clients.withClientDetails(clientDetailsService);
    }

管理令牌

AuthorizationServerTokenService接口定义了一些对令牌进行管理的必要操作,令牌可以被用来加载身份信息,里面包含了这个令牌的相关权限。

实现一个AuthorizationServerTokenServices这个接口,需要继承DefaultTokenServices这个类。该类中包含了一些有用的实现。你可以使用它来修改令牌的格式和令牌的存储。默认情况下,他在创建一个令牌时,是使用随机值来进行填充的。这个类中完成了令牌管理的几乎所有的事情,唯一需要依赖的是spring容器中的一个TokenStore接口实现类来定制令牌持久化。而这个TokenStore,有一个默认的实现,就是ImMemoryTokenStore,这个类会将令牌保存到内存中。除此之外,还有几个默认的TokenStore实现类可以使用。

  • InMemoryTokenStore:这个是默认采用的方式。他可以在单服务器上完美运行(即并发访问压力不大的情况下,并且他在失败时不会进行备份)。大多数的项目都可以使用这个实现类来进行尝试。也可以在并发的时候来进行管理,因为不会被保存到磁盘中,所以更易于调试。
  • JdbcTokenStore:这是一个基于JDBC的实现类,令牌会被保存到关系型数据库中。使用这个实现类,可以在不同的服务器之间共享令牌信息。当然,这个是需要使用spring boot jdbc相关的依赖的。类似的,还有RedisTokenStore基于Redis存储令牌信息。
  • JwtTokenStore:全程是JSON Web Token。他可以把令牌信息全部编码整合进令牌本身,这样后端服务可以不用存储令牌相关信息,这是他最大的优势。但是他也有缺点, 那就是撤销一个已经授权的令牌会非常困难。所以他通常用来处理一个生命周期较短的令牌以及撤销刷新令牌(refresh_token)。而另一个缺点就是这个令牌会比较大,因为他要包含较多的用户凭证信息。JwtTokenStore不会保存任何数据,但是他在转换令牌值以及授权信息方面和DefaultTokenServices所扮演的角色是一样的。

所以我们下面的步骤首先是要定义一个TokenStore

1、注入TokenConfig

我们先定义一个TokenConfig,往Spring容器中注入一个InMemoryTokenStore,生成一个普通令牌。

代码语言:javascript
复制
@Configuration
public class TokenConfig {
    @Bean
    public TokenStore tokenStore(){
        //使用基于内存的普通令牌
        return new InMemoryTokenStore();
    }

2、注入AuthorizationServerTokenService

在AuthorizationServer中定义AuthorizationServerTokenServices

代码语言:javascript
复制
@Autowired
  private TokenStore tokenStore;
  //会通过之前的ClientDetailsServiceConfigurer注入到Spring容器中
  @Autowired
  private ClientDetailsService clientDetailsService;
   
    public AuthorizationServerTokenServices tokenService() {
        DefaultTokenServices service = new DefaultTokenServices();
        service.setClientDetailsService(clientDetailsService); //客户端详情服务
        service.setSupportRefreshToken(true); //允许令牌自动刷新
        service.setTokenStore(tokenStore); //令牌存储策略-内存
        service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
        service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
        return service;
    }
4.3令牌访问端点配置

AuthorizationServerEndpointsConfigurer这个对象的实例可以完成令牌服务以及令牌服务各个endpoint配置。

配置授权类型(Grant Types)

AuthorizationServerEndpointsConfigurer对于不同类型的授权类型,也需要配置不同的属性。

  • authenticationManager:认证管理器。当你选择了password(资源所有者密码)这个授权类型时,就需要指定authenticationManager对象来进行鉴权。
  • userDetailsService:用户主体管理服务。如果设置了这个属性,那说明有一个自己的UserDetailsService接口的实现,或者你可以把这个东东设置到全局域(例如GlobalAuthenticationManagerConfigurer)上去,当你设置了这个之后,那么refresh_token刷新令牌方式的授权类型流程中就会多包含一个检查步骤,来确保这个账号是否仍然有效。
  • authorizationCodeServices:这个属性是用来设置授权服务器的,主要用于 authorization_code 授权码类型模式。
  • implicitGrantService:这个属性用于设置隐式授权模式的状态。
  • tokenGranter:如果设置了这个东东(即TokenGranter接口的实现类),那么授权将会全部交由你来自己掌控,并且会忽略掉以上几个属性。这个属性一般是用作深度拓展用途的,即标准的四种授权模式已经满足不了你的需求时,才会考虑使用这个。

配置授权断点的URL(Endpoint URLS):

AuthorizationServerEndpointsConfifigurer这个配置对象首先可以通过pathMapping()方法来配置断点URL的链接地址。即将oauth默认的连接地址替代成其他的URL链接地址。例如spring security默认的授权同意页面/auth/confirm_access非常简陋,就可以通过passMapping()方法映射成自己定义的授权同意页面。

框架默认的URL链接有如下几个:

/oauth/authorize :授权端点

/auth/token :令牌端点

/oauth/confirm_access :用户确认授权提交的端点

/oauth/error : 授权服务错误信息端点。

/oauth/check_token :用于资源服务访问的令牌进行解析的端点

/oauth/token_key :使用Jwt令牌需要用到的提供公有密钥的端点。

需要注意的是,这几个授权端点应该被Spring Security保护起来只供授权用户访问。

在AuthorizationServer配置令牌访问端点

代码语言:javascript
复制
@Autowired
  private AuthorizationCodeServices authorizationCodeServices;
  @Autowired
  private AuthenticationManager authenticationManager;
   
   @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
//                .pathMapping("/oauth/confirm_access","/customer/confirm_access")//定制授权同意页面
                .authenticationManager(authenticationManager)//认证管理器
                .userDetailsService(userDetailsService)//密码模式的用户信息管理
                .authorizationCodeServices(authorizationCodeServices)//授权码服务
                .tokenServices(tokenService())//令牌管理服务
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
    }
    
        //设置授权码模式的授权码如何存取,暂时用内存方式。
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(){
        return new InMemoryAuthorizationCodeServices();
        //JdbcAuthorizationCodeServices
    }
4.4 令牌端点的安全约束

AuthorizationServerSecurityConfifigurer , 用来配置令牌端点(Token Endpoint)的安全约束,在AuthorizationServer中配置如下:

代码语言:javascript
复制
 @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                .tokenKeyAccess("permitAll()") // oauth/token_key公开
                .checkTokenAccess("permitAll()") // oauth/check_token公开
                .allowFormAuthenticationForClients(); // 表单认证,申请令牌
    }
4.5 授权服务配置总结:

OAuth2的授权服务配置是大家使用Spring Security OAuth最头疼的地方。其实具体的配置方式可以不用着重记忆,翻翻API基本能看懂大概。但是这三块核心的配置对象一定要理解记忆。

1、ClientDetailsServiceConfigurer 配置客户端信息。

2、AuthorizationServerEndpointsConfigurer 配置令牌服务。首选需要配置token如何存取,以及客户端支持哪些类型的token。然后不同的令牌服务需要不同的其他服务。authorization_code类型需要配置authorizationCodeServices来管理授权码,password类型需要UserDetailsService来验证用户身份。

3、AuthorizationServerSecurityConfigurer 对相关endpoint定义一些安全约束。

4.6 web安全配置

完成上面的OAuth配置后,还要注意添加之前Spring Security相关的安全配置。这也是跟之前的Sprnig Security整合的关键。

代码语言:javascript
复制
package com.tuling.security.distributed.uaa.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * 注入一个自定义的配置
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private TokenStore tokenStore;

    @Bean
    public PasswordEncoder passwordEncoder() {
//        return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }
    //从父类加载认证管理器
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(User.withUsername("admin").password(passwordEncoder().encode("admin")).authorities("mobile","salary").build()
                ,User.withUsername("manager").password(passwordEncoder().encode("manager")).authorities("salary").build()
                ,User.withUsername("worker").password(passwordEncoder().encode("worker")).authorities("worker").build());
        return userDetailsManager;
    }

    //配置用户的安全拦截策略
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //链式配置拦截策略
        http.csrf().disable()//关闭csrf跨域检查
                .authorizeRequests()
                .anyRequest().authenticated() //其他请求需要登录
                .and() //并行条件
                .formLogin(); //可从默认的login页面登录,并且登录后跳转到main.html
    }
}
4.7 授权服务流程测试:

用postman访问相关接口获取token。

5.Spring security资源服务配置

前面完成的授权服务实际上是OAuth协议中最复杂的部分,他规定了三方在互不信任的假设下如何进行担保认证。而到了资源服务这一步,其实就比较简单了。资源服务只要在访问资源之前,进行令牌验证即可。

5.1 打开@EnableResourceServer注解

这个注解是Spring Security打开OAuth资源服务的基础注解,可以在启动类或者任意一个@Configuration声明的启动类中打开这个注释。

5.2 资源服务器核心配置

然后,与之前的配置方式类似,Spring Security也提供了ResourceServerConfigurerAdapter适配器来协助完成资源服务器的配置。这个适配器提供了多个configure方法,对以下两个核心对象进行配置。

ResourceServerSecurityConfigurer中主要包含:

  • tokenServices : ResourceServerTokenServices类的实例,用来实现令牌服务,即如何验证令牌。
  • tokenStore :TokenStore类的实例,指定令牌如何访问,与tokenServices配置可选
  • resourceId :这个资源服务的ID,是可选的。但是推荐设置并在授权服务中进行验证。
  • 其他的扩展属性例如tokenExtractor令牌提取器用来提取请求中的令牌。

HttpSecurity,这个配置与Spring Security类似:

  • authorizeRequests()方法验证请求。antMatchers方法匹配访问路径。access()方法配置需要的权限。
  • .sessionManagement()方法配置session管理策略。
  • 其他自定义权限保护规则也通过HttpSecurity来配置。

@EnableResourceServer注解会自动增加一个类型为OAuth2AuthenticationProcessingFilter的过滤器链。

ResourceServerConfig示例内容如下:

代码语言:javascript
复制
package com.tuling.security.distributed.salary.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;

@Configuration
public class MyResourceServerConfig extends ResourceServerConfigurerAdapter {

    public static final String RESOURCE_SALARY = "salary";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId(RESOURCE_SALARY) //资源ID
                .tokenServices(tokenServices()) //使用远程服务验证令牌的服务
                .stateless(true); //无状态模式
    }

    //配置安全策略
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests() //校验请求
                .antMatchers("/order/**") // 路径匹配规则。
                .access("#oauth2.hasScope('all')") // 需要匹配scope
                .and().csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
    //配置access_token远程验证策略。
    public ResourceServerTokenServices tokenServices(){
//        DefaultTokenServices services = new DefaultTokenServices();
        RemoteTokenServices services = new RemoteTokenServices();
        services.setCheckTokenEndpointUrl("http://localhost:53020/uaa/oauth/check_token");
        services.setClientId("c1");
        services.setClientSecret("secret");
        return services;
    }
}

这里需要注意的是ResourceServerSecurityConfigurer的tokenServices()方法,设定了一个token的管理服务。其中,如果资源服务和授权服务是在同一个应用程序上,那可以使用DefaultTokenServices,这样的话,就不用考虑关于实现所有必要的接口一致性的问题。而如果资源服务器是分离的,那就必须要保证能够有匹配授权服务提供的ResourceServerTokenServices,他知道如何对令牌进行解码。

令牌解析方法:使用DefaultTokenServices在资源服务器本地配置令牌存储、解码、解析方式。使用RemoteTokenServices资源服务器通过HTTP请求来解码令牌,每次都请求授权服务器端点/oauth/check_token。这时需要授权服务将这个端点暴露出来,以便资源服务进行访问。所以这里要注意下授权服务的下面这个配置:

代码语言:javascript
复制
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
   security.tokenKeyAccess("permitAll()")// /oauth/token_key 允许访问
   .checkTokenAccess("permitAll()") // /oauth/check_token 允许访问
}

而这个/oauth/check_token端点可以获取到access_token对应到的客户信息。

5.3 编写资源

然后我们编写一个简单的薪水查询接口:

代码语言:javascript
复制
package com.tuling.security.distributed.salary.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("salary")
public class SalaryController {

    @GetMapping("query")
    @PreAuthorize("hasAuthority('salary')")//需要授权客户端拥有order资源才可以访问。
    public String query(){
        return "salary info";
    }
}
5.4 添加安全访问控制

以Spring Security的方式添加安全访问控制策略。

代码语言:javascript
复制
package com.tuling.security.distributed.salary.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/salary/**")
//                .hasAuthority("salary") //这里采用了注解的方法级权限配置。
                .authenticated()
                .anyRequest().permitAll();
    }
}

这里使用了@EnableGlobalMethodSecurity方法打开了基于注解的方法级别的权限验证。

5.5 资源访问测试

到这里,我们的资源服务器就算配置完成了。下面我们来访问资源服务器的salary接口进行测试。测试时要注意,在向资源服务器提交access_token时,需要在请求的headers上添加一个Authorization参数来提交令牌,而令牌的内容需要先加上token的类型Bearer,然后空格,再加上access_token。

首先,直接访问资源路径不带任何参数。http://localhost:53021/resource/salary/query 会返回一个错误内容:

代码语言:javascript
复制
{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}

然后,我们随意提交一个错误的访问令牌。这里要注意的是,在向资源服务器提交access_token时,需要在请求的headers上添加一个Authorization参数来提交令牌,而令牌的内容需要先加上token的类型,是Bearer。然后空格,再加上access_token。

然后,我们重新申请一个正确的access_token,重新访问资源

测试到这里要注意的有两点

一是,要总结下在我们示例代码中验证的资源的要素包含了哪些,这些都是OAuth认证流程中需要注意的概念。包括 clientDetails, resourceId,scope,authorities(其实还可以有roles,只是roles是相当于ROLE_{rolename}格式的资源)。

另一点是关于TokenStore对象。到目前为止,我们在资源服务器中并没有配置TokenStore对象,也就是说,资源服务器并不知道access_token有什么意义。他需要使用RemoteTokenServices将令牌拿到授权服务器上去进行验证才会知道access_token代表的客户信息。这一点在请求量加大后,显然会加重系统的网络负担以及运行效率。而这一点,也是后面的JWT令牌需要解决的问题。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BUG弄潮儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Oauth2简介
    • 实例分析:
      • Oauth2.0认证流程
        • 角色
          • 客户端
          • 资源拥有者
          • 授权服务器
          • 资源服务器
        • 常用术语
          • 1、客户凭证(client Credentials) :客户端的clientId和密码用于认证客户
          • 2、令牌(tokens) :授权服务器在接收到客户请求后,颁发的访问令牌
          • 3、作用域(scopes) :客户请求访问令牌时,由资源拥有者额外指定的细分权限(permission)
        • 令牌类型
          • 1、授权码 :仅用于授权码授权类型,用于交换获取访问令牌和刷新令牌
          • 2、访问令牌 :用于代表一个用户或服务直接去访问受保护的资源
          • 3、刷新令牌 :用于去授权服务器获取一个刷新访问令牌
          • 4、BearerToken :不管谁拿到Token都可以访问资源,类似现金
          • 5、Proof of Possession(PoP) Token :可以校验client是否对Token有明确的拥有权
        • 优缺点:
          • 优点:
          • 缺点:
      • 2.授权模式(常用)
        • 1、授权码模式(Authorization Code)
          • 2、简化授权模式(Implicit)
            • 3、密码模式(Resource Owner PasswordCredentials)
              • 4、客户端模式(Client Credentials)
                • 5、刷新令牌
                • 3.Spring Security Oauth2介绍
                  • 基本介绍
                  • 4.Spring security授权服务配置
                    • 4.1创建配置类
                      • 4.2配置客户端详细信息
                        • 4.3令牌访问端点配置
                          • 4.4 令牌端点的安全约束
                            • 4.5 授权服务配置总结:
                              • 4.6 web安全配置
                                • 4.7 授权服务流程测试:
                                • 5.Spring security资源服务配置
                                  • 5.1 打开@EnableResourceServer注解
                                    • 5.2 资源服务器核心配置
                                      • 5.3 编写资源
                                        • 5.4 添加安全访问控制
                                          • 5.5 资源访问测试
                                          相关产品与服务
                                          访问管理
                                          访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
                                          领券
                                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档