Spring Security OAuth2四种授权模式总结 - Mysql存储客户端信息和令牌(八)

news2024/11/25 18:28:37

写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!如果我的博客对你有帮助,欢迎进行评论✏️✏️、点赞👍👍、收藏⭐️⭐️,满足一下我的虚荣心💖🙏🙏🙏 。

上一篇我们梳理演示了四种授权模式的过程,不过客户端信息、令牌、用户信息等都存在内存中,本篇将客户端信息、令牌、用户身份信息等都存到Mysql数据库中。

本篇环境及代码是在上一篇基础之上,这里只记录主要的改动部分。

目录

完善环境

配置客户端信息存储

配置令牌存储

配置TokenStore

配置令牌服务

配置授权码存取

配置用户认证授权

配置WebSecurityConfigurerAdapter

配置AuthorizationServerEndpointsConfigurer

测试

授权码模式

简化模式

密码模式

客户端模式

完整代码

授权服务

Web安全

Token配置

完善环境

首先我们需要新建表存储客户端信息、令牌等信息,建表语句可以从如下网站找到:

spring-security-oauth/schema.sql at main · spring-attic/spring-security-oauth · GitHub

每个表的作用可以参考本系列的第一篇 Spring Security OAuth2使用步骤(一) 

配置客户端信息存储

首先,我们配置JdbcClientDetailsService使用存取客户端信息,如下:

    @Autowired
    private DataSource dataSource;    
    @Bean
    public ClientDetailsService clientDetails() {
        ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(new BCryptPasswordEncoder());
        return clientDetailsService;
    }

然后,修改ClientDetailsServiceConfigurer配置,如下:

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetails());
    }

配置令牌存储

配置TokenStore

首先,配置TokenStore存储为JdbcTokenStore,如下:

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

配置令牌服务

然后,配置令牌服务,如下:

    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setClientDetailsService(clientDetails());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setTokenStore(tokenStore);
        // 配置令牌和刷新令牌的有效期
        tokenServices.setAccessTokenValiditySeconds(10);
        tokenServices.setRefreshTokenValiditySeconds(10);
        return tokenServices;
    }

配置授权码存取

对于授权码模式,需要配置授权码的存取,如下:

    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
        return new JdbcAuthorizationCodeServices(dataSource);
    }

配置用户认证授权

对于密码模式,申请令牌时提交的用户名密码需要进行验证,验证通过需要给用户授权,用户信息和用户授权需要一个UserDetailsService实现,并在Web安全配置文件中进行配置。

首选,看下UserDetailsService,如下:

@Component
public class CustomUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_admin");
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(simpleGrantedAuthority);
        return new User(username, "$2a$10$bowh1hF9Zwda/O5dUciQde3W6Rk88EP25xC9K9kveFnqFTRFg1n1O", authorities);
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String password = bCryptPasswordEncoder.encode("123456");
        System.out.println(password);
    }
}

以上代码仅仅是测试用的,测试数据:用户名随意,密码123456,使用BCryptPasswordEncoder方式加密后为: $2a$10$bowh1hF9Zwda/O5dUciQde3W6Rk88EP25xC9K9kveFnqFTRFg1n1O, 用户的权限设置为ROLE_admin,真正使用的时候用户名密码还有权限信息这些应该是从数据库中查询或者调用远程服务获取的用户相关信息。

注意oauth2在验证权限的时候会在权限字符串前自动加上 “ROLE_”,所以我们构建authorities时需要自己把ROLE_追加上。

配置WebSecurityConfigurerAdapter

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

配置AuthorizationServerEndpointsConfigurer

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;    

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
        // 密码模式需要
        endpoints.authenticationManager(authenticationManager);
        // 授权码模式需要
        endpoints.authorizationCodeServices(authorizationCodeServices);
        // 令牌管理服务
        endpoints.tokenServices(tokenServices());
    }

至此,基于内存改为数据库的改造就完成了。

测试

下面将测试四种授权模式,每种授权模式的流程及参数参考上一篇 Spring Security OAuth2四种授权模式总结(七)

授权码模式

先清空一下oauth_access_token 、oauth_refresh_token、oauth_code三个表。

浏览器访如下连接:

http://localhost:9005/oauth/authorize?client_id=dev-client&response_type=code&scope=all&redirect_uri=https://www.baidu.com

输入账号:zhangsan  密码:123456,登录进入授权页面:

确认授权后,浏览器重定向到指定路径并附加验证码,code每次都不一样,且用一次就失效,返回的授权码如下:

此时看下数据库oauth_code表,会出现一条记录,如下:

使用该code获取token成功,结果如下:

http://localhost:9005/oauth/token?client_id=dev-client&client_secret=123456&grant_type=authorization_code&code=Lizc1c&redirect_uri=https://www.baidu.com

{

    "access_token": "1b365d33-c7b2-42c2-9eb4-6ccf94c63826",

    "token_type": "bearer",

    "refresh_token": "67b4739b-7d75-4b15-90cb-2a254f267afe",

    "expires_in": 9,

    "scope": "all"

}

此时看下数据库oauth_access_token 、oauth_refresh_token两个表,分别会出现一条记录,如下:

再看下数据库oauth_code表,原本那条数据已经没有了,因为code用一次就会失效删除,如下:

简化模式

先清空一下oauth_access_token 、oauth_refresh_token两个表。

浏览器访如下连接:

http://localhost:9005/oauth/authorize?client_id=dev-client&response_type=token&scope=all&redirect_uri=https://www.baidu.com

输入账号:zhangsan  密码:123456,登录进入授权页面:

确认授权后,浏览器会重定向到指定的redirect_uri路径,并将token存放在uri路径之后。

此时看下数据库oauth_access_token 、oauth_refresh_token两个表,分别会出现一条记录,如下:

密码模式

先清空一下oauth_access_token 、oauth_refresh_token两个表。

使用Postman访问如下连接:

localhost:9005/oauth/token?client_id=dev-client&client_secret=123456&grant_type=password&username=zhangsan&password=123456

此时看下数据库oauth_access_token 、oauth_refresh_token两个表,分别会出现一条记录,如下:

客户端模式

先清空一下oauth_access_token 、oauth_refresh_token两个表。

使用Postman访问如下连接:

localhost:9005/oauth/token?client_id=dev-client&client_secret=123456&grant_type=client_credentials&scopes=all

此时看下数据库oauth_access_token 、oauth_refresh_token两个表,分别会出现一条记录,如下:

完整代码

授权服务

@EnableAuthorizationServer
@Configuration
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private TokenStore tokenStore;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;


    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetails());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
        // 密码模式需要
        endpoints.authenticationManager(authenticationManager);
        // 授权码模式需要
        endpoints.authorizationCodeServices(authorizationCodeServices);
        // 令牌管理服务
        endpoints.tokenServices(tokenServices());

    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
        security.checkTokenAccess("permitAll()");
        security.tokenKeyAccess("permitAll()");
    }

    /**
     * 配置令牌服务
     */
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setClientDetailsService(clientDetails());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setTokenStore(tokenStore);
        // 配置令牌和刷新令牌的有效期
        tokenServices.setAccessTokenValiditySeconds(10);
        tokenServices.setRefreshTokenValiditySeconds(10);
        return tokenServices;
    }

    /**
     * 配置授权码模式的授权码如何存取
     */
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    /**
     * 配置客户端信息如何存取
     */
    @Bean
    public ClientDetailsService clientDetails() {
        ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(new BCryptPasswordEncoder());
        return clientDetailsService;
    }

}

Web安全

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/ignore");
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin").hasAuthority("admin")
                .antMatchers("/common").permitAll()
                .anyRequest().authenticated()
                .and().formLogin()
                .and().csrf().disable();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

}

Token配置

@Configuration
public class TokenConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/373523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3 核心模块源码解析(上)

Vue3相比大家也都有所了解&#xff0c;即使暂时没有使用上&#xff0c;但肯定也学习过&#xff01;Vue3是使用TS进行重写&#xff0c;采用了MonoRepo的管理方式进行管理&#xff0c;本篇文章我们一起来看看 Vue3的使用&#xff0c;与Vue2有什么区别&#xff0c;以及我们该如何优…

【密码学】 一篇文章讲透数字证书

【密码学】 一篇文章讲透数字证书 数字证书介绍 数字证书是一种用于认证网络通信中参与者身份和加密通信的证书&#xff0c;人们可以在网上用它来识别对方的身份。 我们在上一篇博客中介绍了数字签名的作用和原理&#xff0c;数字签名可以防止消息被否认。有了公钥算法和数字签…

史上最全面的软件测试面试题总结(接口、自动化、性能全都有)

目录 思维发散 Linux 测试概念和模型 测试计划与工具 测试用例设计 Web项目 Python基础 算法 逻辑 接口测试 性能测试 总结感谢每一个认真阅读我文章的人&#xff01;&#xff01;&#xff01; 重点&#xff1a;配套学习资料和视频教学 思维发散 一个球&#xff…

二叉树——二叉搜索树的最小绝对差

二叉搜索树的最小绝对差 链接 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 1&#xff1a; 输入&#xff1a;root [4,2,6,1,3] 输出&#xff1a;1 示例 2&…

PowerDesigned16连接Oracle出现“Could not initialize JavaVM“时的解决步骤

PowerDesigned需要连接到数据库&#xff0c;我使用的是oracle&#xff0c;但总是连接不上&#xff0c;输出栏提示"Could not initialize JavaVM"。 经过查找资料&#xff0c;发现是PowerDesigned16是32位的&#xff0c;只能使用32位的JDK来运行JDBC驱动&#xff0c;…

如何从零开始系统的学习项目管理?

经常会有人问&#xff0c;项目管理到底应该学习一些什么&#xff1f;学习考证之后能得到什么价值&#xff1f; 以下我就总结一下内容 一&#xff0c;学习项目管理有用吗&#xff1f; 有效的项目管理带来的益处大致包括以下几个方面&#xff1a;更有效达成业务目标、满足相关…

人工智能轨道交通行业周刊-第35期(2023.2.20-2.26)

本期关键词&#xff1a;重庆智慧轨道、智能运维主机、标准轨距、地方铁路公报、景深、机器视觉应用 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通Rai…

第12天-商品维护(发布商品、商品管理、SPU管理)

1.发布商品流程 发布商品分为5个步骤&#xff1a; 基本信息规格参数销售属性SKU信息保存完成 2.发布商品-基本信息 2.1.会员等级-会员服务 2.1.1.会员服务-网关配置 在网关增加会员服务的路由配置 - id: member_routeuri: lb://gmall-memberpredicates:- Path/api/member/…

学习python第一天---前缀和

一、3956.截断数组&#xff08;前缀和&#xff09;二、前缀和&#xff08;前缀和&#xff09;[0]list(map(int,input().split()))三、子矩阵的和&#xff08;前缀和&#xff09;range(1,n1)四、K倍区间&#xff08;前缀和&#xff09;五、激光炸弹&#xff08;前缀和&#xff0…

模型部署笔记

目录模型部署工作ONNX存在的意义ONNX&#xff08;Open Neural Network Exchange&#xff09;ONNX示例模型推理示例Batch调整量化量化方式常见问题模型部署工作 训练好的模型在特定软硬件平台下推理针对硬件优化和加速的推理代码 训练设备平台&#xff1a; CPU、GPU、DSP ONN…

2023.02.26 学习周报

文章目录摘要文献阅读1.题目2.摘要3.介绍4.模型4.1 SESSION-PARALLEL MINI-BATCHES4.2 SAMPLING ON THE OUTPUT4.3 RANKING LOSS5.实验5.1 数据集5.2 验证方式5.3 baselines5.4 实验结果6.结论深度学习元胞自动机1.定义2.构成3.特性4.思想5.统计特征流形学习1.降维2.空间3.距离…

一些硬件学习的注意事项与快捷方法

xilinx系列软件 系统适用版本 要安装在Ubuntu系统的话&#xff0c;要注意提前看好软件适用的版本&#xff0c;不要随便安好了Ubuntu系统又发现对应版本的xilinx软件不支持。 如下图&#xff0c;发行说明中会说明这个版本的软件所适配的系统版本。 下载 vivado vitis这些都可以…

IT男的一次中年破局尝试--出书

一、转战外企 接上回《人到中年——IT男择业感悟》后&#xff0c;自己从大央企去了某知名外企。外企虽然最近几年的日子已经没有10年前的辉煌与滋润&#xff0c;但相对来说&#xff0c;还能勉强找到工作与生活的平衡点。 划重点&#xff0c;35岁上下的人换工作理由&#xf…

SpringBoot+React博客论坛系统 附带详细运行指导视频

文章目录一、项目演示二、项目介绍三、项目运行截图四、主要代码一、项目演示 项目演示地址&#xff1a; 视频地址 二、项目介绍 项目描述&#xff1a;这是一个基于SpringBootReact框架开发的博客论坛系统。首先&#xff0c;这是一个前后端分离的项目&#xff0c;文章编辑器…

大学物理期末大题专题训练总结-磁学大题

&#xff08;事先声明指的是简单的那个磁学大题&#xff0c;另外一类涉及储存的磁能、磁感应强度分布下次说&#xff09;求个磁通量&#xff0c;求个感应电动势&#xff0c;求个安培力大小......这个感觉是不是像你梦回高中&#xff1f;当然&#xff0c;这一块大题跟高中磁学部…

hadoop-Combiner合并、OutputFormat

一、Combiner合并 Combiner是MR程序中Mapper和Reducer之外的一种组件。 2&#xff09;Combiner组件的父类就是Reducer 3&#xff09;Combiner和Reducer的区别在与运行的位置&#xff1b;Combiner是在每一个MapTask所在的节点运行&#xff1b;Reducer是接收全局所有Mapper的输出…

c++11 标准模板(STL)(std::unordered_set)(九)

定义于头文件 <unordered_set>template< class Key, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator<Key> > class unordered_set;(1)(C11 起)namespace pmr { templat…

Linux学习(8.5)文件内容查阅

目录 文件内容查阅&#xff1a; 直接检视文件内容 cat (concatenate) tac (反向列示) nl (添加行号列印) 可翻页检视 more (一页一页翻动) less (一页一页翻动) 数据撷取 tail (取出后面几行) 非纯文字档&#xff1a; od 修改文件时间或建置新档&#xff1a; touc…

数据结构(六)二叉树

一、树形结构概念树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。它具有以下的特点&#xff1a;1、有一个…

昇腾AI新技能,还能预防猪生病?

国药集团动物保健股份有限公司&#xff08;简称“国药动保”&#xff09;是专业从事动物保健产品研发、生产和销售的国家高新技术企业&#xff0c;是国内少数几家具备新产品原创能力的动物保健企业。其中&#xff0c;猪圆环病毒灭活疫苗等市场份额位居行业前列。 “猪圆环病毒…