【SpringSecurity-2】Springboot + SpringSecurity + Oauth2授权码模式

目录

1、项目验证

(1)获取授权码

(2)获取access_token

2、添加资源服务器

(1)创建项目

(2)添加依赖

(3)创建启动类

(4)配置资源服务器

(5)创建Rest接口

(6)添加application.yml

3、获取token,访问资源服务器

(1)授权服务器的修改

(2)资源服务器 token校验方式


本篇接上篇内容,拿到授权码后,客户端往授权服务器发送请求,携带拿到的授权码,获取对应的access_token,然后可以拿着授权服务器颁发的access_token访问资源服务器。到目前为止,我们暂时只搭建了一个授权服务器,我们通过手动调用接口默认客户端,后续,我们逐步完善。

本篇主要完成的三个任务:

(1)通过获取到的授权码获取access_token

(2)如何搭建一个资源服务器?

(3)通过拿到的access_token如何去访问资源服务器?

1、项目验证

(1)获取授权码

http://localhost:9090/oauth/authorize?client_id=client-code&response_type=code&redirect_uri=http://www.baidu.com

(2)获取access_token

curl --location --request POST 'http://localhost:9090/oauth/token?code=1vnTRV&grant_type=authorization_code&redirect_uri=http://www.baidu.com&scope=read' \
--header 'Authorization: Basic Y2xpZW50LWNvZGU6c2VjcmV0LWNvZGU='

成功获取access_token

{
    "access_token": "14b03e41-643b-4f69-8ef8-d4b614905667",
    "token_type": "bearer",
    "expires_in": 43199,
    "scope": "read"
}

①调用

http://localhost:9090/oauth/token?code=1vnTRV&grant_type=authorization_code&redirect_uri=http://www.baidu.com&scope=read 接口获取access_token

②调用该接口需要配置Header头信息,

Authorization Basic Y2xpZW50LWNvZGU6c2VjcmV0LWNvZGU=

Basic后面的值 是 通过base64对字符串 【clientId:secret】进行加密得到的,即我们在授权服务器中配置的【client-code:secret-code】

③请求参数code 即我们获取到的授权码,其他三个参数是固定的

到此,我们搭建了一个授权服务器,然后通过手动调用的方式拿到了access_token。我们调用过程中相当于客户端(client)在与授权服务器进行交互。

2、添加资源服务器

创建一个资源服务器,与授权服务器分离

(1)创建项目

(2)添加依赖

pom.xml中添加依赖,特别说明这是一个父子项目,父pom中添加了spring-boot-dependencies 依赖

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.3.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

子项目中oauth2code-resource-server中添加依赖如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId>
        <version>2.3.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

(3)创建启动类

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

(4)配置资源服务器

创建ResourceConfig配置类

@Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {

    // token校验地址 授权服务器地址
    private static final String URL_CHECK_TOKEN = "http://localhost:9090/oauth/check_token";
    // 分配给资源服务器的clientId
    private static final String R_CLIENT_ID = "client-code";
    // 分配给资源服务器的SECRET
    private static final String R_SECRET = "secret-code";


    @Bean
    public RemoteTokenServices remoteTokenServices () {
        final RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setCheckTokenEndpointUrl(URL_CHECK_TOKEN);
        remoteTokenServices.setClientId(R_CLIENT_ID);
        remoteTokenServices.setClientSecret(R_SECRET);
        return remoteTokenServices;
    }

    /**
      * 资源服务器访问配置
      * TODO 方法描述
      * @param http
      * @return void
      **/
    @Override
    public void configure(HttpSecurity http) throws Exception{
        // 创建session策略
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        // 所有请求都要授权
        http.authorizeRequests().anyRequest().authenticated();
    }

    /**
      * 资源服务器配置
      * TODO 方法描述
      * @param resource
      * @return void
      **/
    @Override
    public void configure(ResourceServerSecurityConfigurer resource) {
        resource.resourceId("test") // 设置 资源服务器id
                .stateless(true) //
                .tokenServices(remoteTokenServices()); // 通过远程调用的方式进行token校验;也可以使用tokenstore的方式进行校验
    }
}

①注解@Configuration和@EnableResourceServer开启资源服务器

②重写ResourceServerConfigurerAdapter 自定义资源服务器配置

③配置configure(HttpSecurity http)方法,这里可以代替Spring Security同名方法配置,开启所有请求需要授权才可访问

httpsecurity session管理Spring Security Config : HttpSecurity安全配置器 SessionManagementConfigurer_enablesessionurlrewriting-优快云博客

④configure(ResourceServerSecurityConfigurer resource)资源配置相关,这里配置了resourId/tokenService通过远程调用方式进行token校验

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

        

  • 请求匹配器,用来设置需要进行保护的资源路径,默认的情况下是保护资源服务的全部路径。
  • 通过 http.authorizeRequests()来设置受保护资源的访问规则
  • 其他的自定义权限保护规则通过 HttpSecurity 来进行配置。

(5)创建Rest接口

@RestController
@RequestMapping("api")
public class IndexController {

    @GetMapping("test")
    public Object test() {
        return "success";
    }

}

(6)添加application.yml

简单配置了端口号

server:
  port: 9081

项目最终的结构如下图:

这样我们就创建完成一个资源服务器,并对外暴露了一个rest接口,需要通过携带token进行访问。

3、获取token,访问资源服务器

接下来我们从头走一边,先通过客户端(手动)获取授权码,拿着授权码去授权服务器获取token,然后拿着token去访问资源服务器对外暴露的rest接口。

(1)授权服务器的修改

在上面操作过程中,对授权服务器做了一点处理,添加了认证服务器的一些配置

/**
  * 认证服务器配置
  * 资源服务器配置了tokenservice后,访问check_token、token_key时不需要授权访问
  * @param server
  * @return void
  **/
@Override
public void configure(AuthorizationServerSecurityConfigurer server) {
    server.tokenKeyAccess("permitAll()") // 获取tokenkey的接口不需要授权访问
            .checkTokenAccess("permitAll()") // 进行token校验的接口不需要授权访问
            .allowFormAuthenticationForClients();
}

因为我们在资源服务器端进行token验证是通过配置RemoteTokenServices 这种形式进行的,而且是两端分离的,所以在认证服务器端需要放开认证权限(或添加适当的认证资源)。不然在访问资源服务器的rest接口时会报错,如下:

报错信息很明显,没有访问check_token的权限。

其实这里我们也可以配置该客户端拥有的资源权限进行限制,比如添加 “是否拥有某种资源”。比如使用hasAnyAuthority('CLIENT') 表示访问 /oauth/check_token时是否拥有CLIENT权限,显然我们在授权服务器的 AuthorizationServerConfig配置文件中对ClientDetailsServiceConfigurer中的配置添加了client(client-code) 拥有资源CLIENT。

/**
  * 认证服务器配置
  * 资源服务器配置了tokenservice后,访问check_token、token_key时不需要授权访问
  * @param server
  * @return void
  **/
@Override
public void configure(AuthorizationServerSecurityConfigurer server) {
    server.tokenKeyAccess("permitAll()") // 获取tokenkey的接口不需要授权访问
            .checkTokenAccess("hasAnyAuthority('CLIENT')") // 进行token校验的接口需要有CLIENT这个资源权限
                                                            // 这里的CLIENT 是授权服务器 ClientDetailsServiceConfigurer中配置的client的authorities
            .allowFormAuthenticationForClients();
}

说到这里,需要了解下authorities/scope

scope:表示权限范围,可选项,用户授权页面时进行选择

authorities:授予client的权限

(2)资源服务器 token校验方式

现在资源服务器的token校验使用的tokenservice 方式,还有tokenStore、tokenExtractor

tokenServices :ResourceServerTokenServices 类的实例,用来实现令牌服务。

tokenStore :TokenStore类的实例,指定令牌如何访问,与tokenServices配置可选。

tokenExtractor 令牌提取器用来提取请求中的令牌。

tokenService():是配置访问资源服务时传过来的令牌解析服务,有两种情况:

资源服务器和认证服务器在一起,这是只需要配置默认的DefaultTokenServices即可,但是要注意必须配置一个TokenStore,即是认证服务器中存储令牌的配置,在本地进行解析验证。

资源服务器和认证服务器不在一起,如微服务中的单独认证服务器和多个资源服务器,这是我们需要配置远程令牌访问解析服务RemoteTokenServices ,配置token的验证端点/oauth/check_token,最终将其配置到资源服务器。要注意的是,一定要在认证服务器中开启相应的端点:

@Override

public void configure(AuthorizationServerSecurityConfigurer security) {

security

// /oauth/token_key公开

.tokenKeyAccess("permitAll()")

// /oauth/check_token公开

.checkTokenAccess("permitAll()")

.allowFormAuthenticationForClients();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dabing9

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值