基于 Oauth2 搭建微服务 API 开放平台第 3 篇 —— 搭建资源服务 order-server(完结)

 

在上一篇博客基础上,我们继续搭建资源服务:https://blog.csdn.net/BiandanLoveyou/article/details/117593433

注意:

市面上很多教学课程和很多博客都是在代码里写固定用户名和密码,或者配置客户端的服务都是使用内存的形式 clients.inMemory(),因此很多问题都屏蔽掉了!

今天我们演示的是从数据库里读取数据,而不是写固定在代码里,因此参考价值很高!实际项目中,也可以换成 Redis 做数据源。这里为了方便学习,使用数据库了。

整体代码结构:

application.xml 配置(需要有数据库的配置,且与授权认证中心的属于同一套数据库。实际项目中,授权中心和资源服务应该分开部署):

server:
  port: 8081

# 将SpringBoot项目作为单实例部署调试时,不需要注册到注册中心
eureka:
  client:
    fetch-registry: false
    register-with-eureka: false

spring:
  application:
    name: order-server
  # 数据源配置
  datasource:
    # 使用阿里巴巴的 druid 数据源
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/study_oauth2?characterEncoding=utf-8
      username: root
      password: root
  #  security 配置
  security:
    oauth2:
      resource:
        # 从认证授权中心上验证 token
        tokenInfoUri: http://127.0.0.1:8080/oauth/check_token
        preferTokenInfo: true
      client:
        accessTokenUri: http://127.0.0.1:8080/oauth/token
        userAuthorizationUri: http://127.0.0.1:8080/oauth/authorize
        clientId: good123
        clientSecret: 123

ResourceServerConfiguration 代码:

package com.study.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;

/**
 * @author biandan
 * @description
 * @signature 让天下没有难写的代码
 * @create 2021-06-06 下午 1:39
 */
@Configuration
@EnableResourceServer //开启资源服务中心
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 对 api/order 请求进行拦截 验证 accessToken
        http.authorizeRequests().antMatchers("/api/order/**").authenticated();
    }
}

TokenStore 的配置,注意:默认使用内存的方式 clients.inMemory(),因为我们认证中心是使用数据库的方式,因此这里必须配置相同的认证方式。

package com.study.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import javax.sql.DataSource;

/**
 * @author biandan
 * @description
 * @signature 让天下没有难写的代码
 * @create 2021-06-05 下午 3:39
 */
@Configuration
public class TokenStoreConfig {

    @Autowired
    private DataSource dataSource;

    //设置保存token的方式,一共有五种,这里采用数据库的方式
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }
}

UserEntity 代码(参考认证中心的):

package com.study.entity;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.List;

/**
 * @author biandan
 * @description 用户实体类,需要实现 UserDetails 接口
 * @signature 让天下没有难写的代码
 * @create 2021-05-31 下午 12:43
 */
public class UserEntity implements UserDetails {

    private Integer id;

    //用户名
    private String username;

    //密码
    private String password;

    //用户所有权限集合
    private List<GrantedAuthority> authorities = new ArrayList<>();

    //是否生效,1=true,0=false
    private boolean enabled;

    //是否未过期,1=true,0=false
    private boolean accountNonExpired;

    //是否未锁定,1=true,0=false
    private boolean accountNonLocked;

    //证书是否未过期,1=true,0=false
    private boolean credentialsNonExpired;

    省略 get、set 方法,请补上
}

注意:

这里必须要加上 UserEntity 这个实体类,且包的路径必须与认证中心的一致,这样才能反序列化。否则报错:

 

OrderController:

package com.study.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author biandan
 * @description
 * @signature 让天下没有难写的代码
 * @create 2021-06-06 下午 1:40
 */
@RestController
@RequestMapping("/api/order")
public class OrderController {

    private static final SimpleDateFormat SDf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @RequestMapping("/getInfo")
    public String getInfo(){
        return "现在是北京时间:" + SDf.format(new Date());
    }
}

 

启动类:

package com.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author biandan
 * @description
 * @signature 让天下没有难写的代码
 * @create 2021-06-06 下午 1:36
 */
@SpringBootApplication
public class OrderApplication {

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

测试:把有效的 access_token 放在 Headers 的 Authorization 上,VALUE 值的前面增加 bearer 和一个空格。 

 

 

题外话:

TokenStore 的配置默认使用内存的方式 clients.inMemory(),我们可以找到 DefaultTokenServices.classloadAuthentication 方法,打上断点跟踪。如果不设置其它的方式,默认使用内存方式,如图:

如果资源服务和认证中心的 TokenStore 方式不一致,会在校验 access_token 的时候一直报错 Invalid access token,虽然我们通过校验 token 是正确的,但是在内存里是找不到这个 token 的,存入数据库了。

{
    "error": "invalid_token",
    "error_description": "Invalid access token: ce14a553-60e3-4a7c-a719-5522b09d22a8"
}

 

因此我们增加了 TokenStoreConfig 类之后,就使用的是我们指定的 JdbcTokenStore 方式了。如图:

 

OK,基于 Oauth2 搭建微服务 API 开放平台讲解到这。

 

本篇博客代码(内附数据库表):https://pan.baidu.com/s/1A9JkphSV3WnHxm5Ut2C-FA  提取码:26d3

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值