当前位置: 首页 > news >正文

spring security OAuth2 搭建资源服务器以及授权服务器/jdbc/jwt两种方案

一、认证服务器基于jdbc方式

如果不懂请移步上一篇文章:Spring security OAuth2 授权服务器搭建-CSDN博客

    在上一篇文章中,TokenStore的默认实现为 InHenoryTokenStore 即内存存储,对于 CLient 信息,userDetaitsServce 接负责从存储库中读取数据,在上面的案例中默认使用的也是 InHemoryCLientDetalsService 实现类。如果要想使用政据库存储,只要提供这些接口的实现类即可,而框架已经为我们写好 dbekenStore 和 dbcclientDetatsService

1.1 数据库所需表

我们使用spring security 自带的sql 语句生成对应的表结构,我们关注一下 oauth_client_details  这个表,这个表用来储存用户密钥信息,相当于前面的这个地方

clients.inMemory() //基于内存,后期可以入库查出来.withClient("client-lq").secret(passwordEncoder.encode("secret-lq"))

-- 写入客户端信息
INSERT INTO oauth_client_details
VALUES ('client-id', NULL,'$2a$10$2McX6ml8CVK3RUNpLkX1zeQeNkrEvLCPOJ2hhpG18XMeIMbJWIJnK', 'read', 'authorization_code,refresh_token','http://www.baidu.com',NULL, NULL, NULL, NULL,NULL);

client_secret 需要加密存进去,否则会报不成功

--  structure for clientdetailsDROP TABLE IF EXISTS `clientdetails`;
CREATE TABLE clientdetails (appId                  varchar(256) NOT NULL,resourceIds            varchar(256)  DEFAULT NULL,appSecret              varchar(256)  DEFAULT NULL,scope                  varchar(256)  DEFAULT NULL,grantTypes             varchar(256)  DEFAULT NULL,redirectUrl            varchar(256)  DEFAULT NULL,authorities            varchar(256)  DEFAULT NULL,access_token_validity  int(11)       DEFAULT NULL,refresh_token_validity int(11)       DEFAULT NULL,additionalInformation  varchar(4096) DEFAULT NULL,autoApproveScopes      varchar(256)  DEFAULT NULL,PRIMARY KEY (appId)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- Table structure for oauth_access_token
DROP TABLE IF EXISTS oauth_access_token;
CREATE TABLE oauth_access_token  (token_id varchar(256) DEFAULT NULL,token blob,authentication_id varchar(256) NOT NULL,user_name     varchar(256) DEFAULT NULL,client_id     varchar(256) DEFAULT NULL,authentication blob ,refresh_token  varchar(256) DEFAULT NULL,PRIMARY KEY (authentication_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;--  Table structure for oauth_approvalsDROP TABLE IF EXISTS  oauth_approvals;
CREATE TABLE oauth_approvals (userId varchar(256) DEFAULT NULL,clientId varchar(256) DEFAULT NULL,scope varchar(256) DEFAULT NULL,status varchar(10) DEFAULT NULL,expiresAt timestamp NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,lastModifiedAt date null
)ENGINE=InnODB DEFAULT CHARSET=utf8mb4;-- Table structure for oauth_client_details
DROP TABLE IF EXISTS oauth_client_details;
CREATE TABLE oauth_client_details (client_id               varchar(256) NOT NULL,resource_ids            varchar(256)  DEFAULT NULL,client_secret           varchar(256)  DEFAULT NULL,scope                   varchar(256)  DEFAULT NULL,authorized_grant_types  varchar(256)  DEFAULT NULL,web_server_redirect_uri varchar(256)  DEFAULT NULL,authorities             varchar(256)  DEFAULT NULL,access_token_validity   int(11)       DEFAULT NULL,refresh_token_validity  int(11)       DEFAULT NULL,additional_information  varchar(4096) DEFAULT NULL,autoapprove             varchar(256)  DEFAULT NULL,PRIMARY KEY (client_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;--  Table structure for oauth_clienttoken
DROP TABLE IF EXISTS  oauth_client_token;
CREATE TABLE oauth_client_token (token_id          varchar(256) DEFAULT NULL,token             blob,authentication_id varchar(256) NOT NULL,user_nam          varchar(256) DEFAULT NULL,client_id         varchar(256) DEFAULT NULL,PRIMARY KEY (authentication_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;--  Table structure for oauth_code
DROP TABLE IF EXISTS oauth_code;
CREATE TABLE oauth_code (code           varchar(256) DEFAULT NULL,authentication blob
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- Table structure for oauth_refresh_token
DROP TABLE IF EXISTS  oauth_refresh_token;
CREATE TABLE oauth_refresh_token (
token_id varchar(256) DEFAULT NULL,
token blob,
authentication blob
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;select * from  oauth_refresh_token;-- 写入客户端信息
INSERT INTO oauth_client_details
VALUES ('client-id', NULL,'$2a$10$2McX6ml8CVK3RUNpLkX1zeQeNkrEvLCPOJ2hhpG18XMeIMbJWIJnK', 'read', 'authorization_code,refresh_token','http://www.baidu.com',NULL, NULL, NULL, NULL,NULL);

1.2 认证服务器配置

@Configuration
@EnableAuthorizationServer  //指定当前应用为授权服务器
public class JdbcAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {private final PasswordEncoder passwordEncoder;private final UserDetailsService userDetailsService;private final AuthenticationManager authenticationManager;private final DataSource dataSource;@Autowiredpublic JdbcAuthorizationServerConfig(PasswordEncoder passwordEncoder, UserDetailsService userDetailsService, AuthenticationManager authenticationManager, DataSource dataSource) {this.passwordEncoder = passwordEncoder;this.userDetailsService = userDetailsService;this.authenticationManager = authenticationManager;this.dataSource = dataSource;}@Beanpublic ClientDetailsService clientDetails() {JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);// 使用哪一种加密方式clientDetailsService.setPasswordEncoder(passwordEncoder);return clientDetailsService;}// 用来配置授权服务器可以为哪些客户端授权   client_id,secret  redirect_url@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(clientDetails());// 使用jdbc存储}@Beanpublic TokenStore tokenStore() {JdbcTokenStore jdbcTokenStore = new JdbcTokenStore(dataSource);return jdbcTokenStore;}// 配置令牌存储@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager);endpoints.tokenStore(tokenStore());// 配置令牌存储为数据库存储endpoints.userDetailsService(userDetailsService);// 配置 tokenServices 参数DefaultTokenServices tokenServices = new DefaultTokenServices();//修改默认令牌生成服务tokenServices.setTokenStore(endpoints.getTokenStore());// 基于数据库令牌生成tokenServices.setSupportRefreshToken(true);//是否支持刷新令牌tokenServices.setReuseRefreshToken(true); // 是否重复使用刷新令牌( 直到过期tokenServices.setClientDetailsService(endpoints.getClientDetailsService());//设置客户端信息tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());//用来控制令牌存储增强策略// 访问令牌的默认有效期( 以秒为单位)。过期的令牌为零或负数。tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30)); // 30天endpoints.tokenServices(tokenServices);// 使用配置令牌服务}}

1.3 security 配置

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic UserDetailsService userDetailsService() {InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password(passwordEncoder().encode("123456")).roles("ADMIN").build());return inMemoryUserDetailsManager;}@Override@Beanprotected AuthenticationManager authenticationManager() throws Exception {return super.authenticationManager();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin()// 开启表单登录.and().csrf().disable();}
}

1.4 数据库配置

@Configuration
@Slf4j
public class MysqlDsConfig {/***  配置数据源* @return*/@Primary@Beanpublic DataSource mysqlDataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/oauth3");dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUsername("root");dataSource.setPassword("12345678");return dataSource;}}

1.5 启动测试

当我们刷新token的时候 oauth_refresh_token 会有值进去,使用 apifox 测试令牌


二、资源服务器基于 jdbc 方式

需要连接数据库信息,跟认证服务器数据源一样,因为资源服务器最终也要去读取表信息

所需的依赖,资料参考 哔哩博主,不良人编程 

<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-cloud.version>Hoxton.SR9</spring-cloud.version><spring-boot.version>2.3.7.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-resource-server</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- 数据源支持 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.8</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

2.1  资源服务器配置

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {private final DataSource dataSource;@Autowiredpublic ResourceServerConfig(DataSource dataSource) {this.dataSource = dataSource;}@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {resources.tokenStore(tokenStore());}public TokenStore tokenStore() {return new JdbcTokenStore(dataSource);}
}

2.2 测试controller

@RestController
public class HelloController {@RequestMapping("hello")public String hello() {System.out.println("hello resource server ");return "hello resource server";}
}

2.3 测试结果

当我们这个时候访问的时候就需要带上 Authorization:Bearer   参数,否则提示 Full authentication is required to access this resource 

curl -H "Authorization:Bearer token 对应的值" http://127.0.0.1:8083/hello


三、认证服务器基于 jwt 方式

jwt 分为三部分,用三个点隔开  ,第一部分标识 header 标识用那种加密方式;中间部分为subject 主体信息,可以是用户信息,也可以是一个json数据;最后一部分为sign 签名信息,这个信息需要设置足够复杂才能被破解;

3.1 认证服务器配置

可能在疑问,为什么还是要用数据库,这次我们只需要从库里面读取一次用户信息,只是使用一张表 oauth_client_details 其他信息都不会使用,jwt 有自动过期时间

@Configuration
@EnableAuthorizationServer  //指定当前应用为授权服务器
public class JwtAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {private final PasswordEncoder passwordEncoder;private final UserDetailsService userDetailsService;private final AuthenticationManager authenticationManager;private final DataSource dataSource;@Autowiredpublic JwtAuthorizationServerConfig(PasswordEncoder passwordEncoder, UserDetailsService userDetailsService, AuthenticationManager authenticationManager, DataSource dataSource) {this.passwordEncoder = passwordEncoder;this.userDetailsService = userDetailsService;this.authenticationManager = authenticationManager;this.dataSource = dataSource;}@Beanpublic ClientDetailsService clientDetails() {JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);// 使用哪一种加密方式clientDetailsService.setPasswordEncoder(passwordEncoder);return clientDetailsService;}// 用来配置授权服务器可以为哪些客户端授权   client_id,secret  redirect_url@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(clientDetails());// 使用jdbc存储}// 使用同一个秘钥编码@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter() {JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();jwtAccessTokenConverter.setSigningKey("12332111");return jwtAccessTokenConverter;}// jwt生成方式生成令牌@Beanpublic TokenStore tokenStore() {JwtTokenStore jdbcTokenStore = new JwtTokenStore(jwtAccessTokenConverter());return jdbcTokenStore;}// 配置令牌存储@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager);endpoints.tokenStore(tokenStore())// 配置jwt令牌存储为数据库存储.accessTokenConverter(jwtAccessTokenConverter());}//http://127.0.0.1:8082/oauth/authorize?client_id=client&response_type=code&redirect_url=https://www.baidu.com}

3.2 测试效果

1、页面授权效果有所不同,获取code

2、返回的令牌有所不同

api fox 效果

四、资源服务器基于 jwt 方式

    我们只需要跟认证服务器加密规则设置相同即可,因为jwt 自带加密算法,就类似于我们两个定义了一套rsa的秘钥,我们加密规则相同,约定一个签名戳,这个别人获取不到,你请求过来的时候我验证合法性,所以就不需要用到数据库了

4.1 资源服务器配置

@Configuration
@EnableResourceServer
public class JwtResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {resources.tokenStore(tokenStore());}// jwt生成方式生成令牌@Beanpublic TokenStore tokenStore() {JwtTokenStore jdbcTokenStore = new JwtTokenStore(jwtAccessTokenConverter());return jdbcTokenStore;}// 使用同一个秘钥编码@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter() {JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();jwtAccessTokenConverter.setSigningKey("12332111");return jwtAccessTokenConverter;}
}

4.2 测试效果

curl -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjYzMTY1MTAsInVzZXJfbmFtZ
SI6InJvb3QiLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjEyYTgyMmNhLWQ3MTgtNDE1Yy1hYWQ3LTA5ZjIxODNjNzY0YiIsImNsaWVudF9pZCI6ImNsaWVudC1scSIsInNjb3BlI
jpbInJlYWQ6dXNlciJdfQ.myzFE0VJOhlFLOsddBknOeB6Y499RwZ1X2zTM4PxC00" http://127.0.0.1:8083/hello
 

Z1X2zTM4PxC00" http://127.0.0.1:8083/hello
hello resource server
D:\java-tool\idea-project\spring-security-study>
 

使用apifox 测试

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Spark性能调优】长尾任务如何优化
  • robosuite基础教程(一)——基本概念
  • 如何解决“json schema validation error ”错误? -- HarmonyOS自学6
  • fiddler抓包01:工具介绍
  • 时序必读论文11|ICLR23 TimesNet时间序列分析的二维变化建模
  • Https AK--(ssl 安全感满满)
  • 24.9.16数据结构|平衡二叉树
  • uniapp中实现<text>文本内容点击可复制或拨打电话
  • Miracast/WifiDisplay开发相关的深入调研分析-android投屏实战开发
  • PMP--一模--解题--111-120
  • 数据结构-链表
  • 【Java集合】ArrayList
  • Java HashMap 总结
  • LeetCode-160.相交链表
  • C#学习笔记(三)Visual Studio安装与使用
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • CentOS从零开始部署Nodejs项目
  • Idea+maven+scala构建包并在spark on yarn 运行
  • Logstash 参考指南(目录)
  • pdf文件如何在线转换为jpg图片
  • vue.js框架原理浅析
  • zookeeper系列(七)实战分布式命名服务
  • 创建一种深思熟虑的文化
  • 聊一聊前端的监控
  • 排序算法学习笔记
  • 少走弯路,给Java 1~5 年程序员的建议
  • 我这样减少了26.5M Java内存!
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 异常机制详解
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • ​人工智能书单(数学基础篇)
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • # centos7下FFmpeg环境部署记录
  • ## 基础知识
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • (23)Linux的软硬连接
  • (C语言)二分查找 超详细
  • (day 12)JavaScript学习笔记(数组3)
  • (Git) gitignore基础使用
  • (Java入门)学生管理系统
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (苍穹外卖)day03菜品管理
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (南京观海微电子)——COF介绍
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .NET Framework与.NET Framework SDK有什么不同?
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .NET Standard 的管理策略
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • @RequestMapping 和 @GetMapping等子注解的区别及其用法
  • [2021ICPC济南 L] Strange Series (Bell 数 多项式exp)
  • [AIGC] Redis基础命令集详细介绍