springboot+oauth2

2023-11-04

SPRING BOOT + OAUTH2.0 + jdbc
o(╯□╰)o

搞了几天springboot的security 下的 oauth2.0,之前没接触过springboot 和security,spring boot OAUTH2.0 官方文档也解释的不是很到位,这里写了个demo备忘一下,OAUTH2.0的概念就不再阐述了:
- 协议文档:https://github.com/jeansfish/RFC6749.zh-cn
- 官方demo:https://github.com/spring-guides/tut-spring-boot-oauth2

sql脚本

CREATE SCHEMA IF NOT EXISTS `test-oauth` DEFAULT CHARACTER SET utf8 ;
        USE `test-oauth` ;

        -- -----------------------------------------------------
        -- Table `test-oauth`.`clientdetails`
        -- -----------------------------------------------------
        CREATE TABLE IF NOT EXISTS `test-oauth`.`clientdetails` (
        `appId` VARCHAR(128) NOT NULL,
        `resourceIds` VARCHAR(256) NULL DEFAULT NULL,
        `appSecret` VARCHAR(256) NULL DEFAULT NULL,
        `scope` VARCHAR(256) NULL DEFAULT NULL,
        `grantTypes` VARCHAR(256) NULL DEFAULT NULL,
        `redirectUrl` VARCHAR(256) NULL DEFAULT NULL,
        `authorities` VARCHAR(256) NULL DEFAULT NULL,
        `access_token_validity` INT(11) NULL DEFAULT NULL,
        `refresh_token_validity` INT(11) NULL DEFAULT NULL,
        `additionalInformation` VARCHAR(4096) NULL DEFAULT NULL,
        `autoApproveScopes` VARCHAR(256) NULL DEFAULT NULL,
        PRIMARY KEY (`appId`))
        ENGINE = InnoDB
        DEFAULT CHARACTER SET = utf8;


        -- -----------------------------------------------------
        -- Table `test-oauth`.`oauth_access_token`
        -- -----------------------------------------------------
        CREATE TABLE IF NOT EXISTS `test-oauth`.`oauth_access_token` (
        `token_id` VARCHAR(256) NULL DEFAULT NULL,
        `token` BLOB NULL DEFAULT NULL,
        `authentication_id` VARCHAR(128) NOT NULL,
        `user_name` VARCHAR(256) NULL DEFAULT NULL,
        `client_id` VARCHAR(256) NULL DEFAULT NULL,
        `authentication` BLOB NULL DEFAULT NULL,
        `refresh_token` VARCHAR(256) NULL DEFAULT NULL,
        PRIMARY KEY (`authentication_id`))
        ENGINE = InnoDB
        DEFAULT CHARACTER SET = utf8;


        -- -----------------------------------------------------
        -- Table `test-oauth`.`oauth_approvals`
        -- -----------------------------------------------------
        CREATE TABLE IF NOT EXISTS `test-oauth`.`oauth_approvals` (
        `userId` VARCHAR(256) NULL DEFAULT NULL,
        `clientId` VARCHAR(256) NULL DEFAULT NULL,
        `scope` VARCHAR(256) NULL DEFAULT NULL,
        `status` VARCHAR(10) NULL DEFAULT NULL,
        `expiresAt` DATETIME NULL DEFAULT NULL,
        `lastModifiedAt` DATETIME NULL DEFAULT NULL)
        ENGINE = InnoDB
        DEFAULT CHARACTER SET = utf8;


        -- -----------------------------------------------------
        -- Table `test-oauth`.`oauth_client_details`
        -- -----------------------------------------------------
        CREATE TABLE IF NOT EXISTS `test-oauth`.`oauth_client_details` (
        `client_id` VARCHAR(128) NOT NULL,
        `resource_ids` VARCHAR(256) NULL DEFAULT NULL,
        `client_secret` VARCHAR(256) NULL DEFAULT NULL,
        `scope` VARCHAR(256) NULL DEFAULT NULL,
        `authorized_grant_types` VARCHAR(256) NULL DEFAULT NULL,
        `web_server_redirect_uri` VARCHAR(256) NULL DEFAULT NULL,
        `authorities` VARCHAR(256) NULL DEFAULT NULL,
        `access_token_validity` INT(11) NULL DEFAULT NULL,
        `refresh_token_validity` INT(11) NULL DEFAULT NULL,
        `additional_information` VARCHAR(4096) NULL DEFAULT NULL,
        `autoapprove` VARCHAR(256) NULL DEFAULT NULL,
        PRIMARY KEY (`client_id`))
        ENGINE = InnoDB
        DEFAULT CHARACTER SET = utf8;


        -- -----------------------------------------------------
        -- Table `test-oauth`.`oauth_client_token`
        -- -----------------------------------------------------
        CREATE TABLE IF NOT EXISTS `test-oauth`.`oauth_client_token` (
        `token_id` VARCHAR(256) NULL DEFAULT NULL,
        `token` BLOB NULL DEFAULT NULL,
        `authentication_id` VARCHAR(128) NOT NULL,
        `user_name` VARCHAR(256) NULL DEFAULT NULL,
        `client_id` VARCHAR(256) NULL DEFAULT NULL,
        PRIMARY KEY (`authentication_id`))
        ENGINE = InnoDB
        DEFAULT CHARACTER SET = utf8;


        -- -----------------------------------------------------
        -- Table `test-oauth`.`oauth_code`
        -- -----------------------------------------------------
        CREATE TABLE IF NOT EXISTS `test-oauth`.`oauth_code` (
        `code` VARCHAR(256) NULL DEFAULT NULL,
        `authentication` BLOB NULL DEFAULT NULL)
        ENGINE = InnoDB
        DEFAULT CHARACTER SET = utf8;


        -- -----------------------------------------------------
        -- Table `test-oauth`.`oauth_refresh_token`
        -- -----------------------------------------------------
        CREATE TABLE IF NOT EXISTS `test-oauth`.`oauth_refresh_token` (
        `token_id` VARCHAR(256) NULL DEFAULT NULL,
        `token` BLOB NULL DEFAULT NULL,
        `authentication` BLOB NULL DEFAULT NULL)
        ENGINE = InnoDB
        DEFAULT CHARACTER SET = utf8;


authorization server
//EnableAuthorizationServer注解 来表示授权服务
@SpringBootApplication
@EnableAuthorizationServer
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

重写AuthorizationServerConfigurerAdapter类 配置token相关参数 初始化 tokenStore authenticationManager clientDetailsService,这里都是用的框架提供的模板,也可查看模板源码,根据其接口自己实现持久层,


/**
 * AuthorizationServerConfigurer 需要配置三个配置-重写几个方法:
 * ClientDetailsServiceConfigurer:用于配置客户详情服务,指定存储位置
 * AuthorizationServerSecurityConfigurer:定义安全约束
 * AuthorizationServerEndpointsConfigurer:定义认证和token服务
 *
 */
@Configuration
public class OAuthServerConfigurer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;

    @Autowired
    @Qualifier("clientDetailsServiceImpl")
    private ClientDetailsService clientDetailsService;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //指定认证管理器
        endpoints.authenticationManager(authenticationManager);
        //指定token存储位置
        endpoints.tokenStore(tokenStore());

        // 自定义token生成方式 可以根据 业务信息生成
        //TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        //tokenEnhancerChain.setTokenEnhancers(Arrays.asList(customerEnhancer(), accessTokenConverter()));
        //endpoints.tokenEnhancer(tokenEnhancerChain);


        // 配置TokenServices参数
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(endpoints.getTokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        tokenServices.setAccessTokenValiditySeconds( (int) TimeUnit.DAYS.toSeconds(3000)); // 3000天
        endpoints.tokenServices(tokenServices);
        super.configure(endpoints);

    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("permitAll()");
        security.allowFormAuthenticationForClients();//允许client使用form的方式进行authentication的授权
    }

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

    }

    /**
     * 定义clientDetails存储的方式,注入DataSource
     * @return
     */
    @Bean
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }


    /**
     * 指定token存储的位置
     * @return
     */
    @Bean
    public TokenStore tokenStore() {
       // return new InMemoryTokenStore();
        //return new RedisTokenStore(redisConnectionFactory);
        return new JdbcTokenStore(dataSource);
    }


    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

}

实现 UserDetailsService 接口,spring security 登录验证需要,具体源码位于AbstractUserDetailsAuthenticationProvider类authenticate方法
而其又在org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter中被调用,这里不再多阐述可以自己去了解spring security

@Service
public class UserDetailsServiceImpl implements UserDetailsService {


    @Autowired
    DataSource dataSource;

    JdbcTemplate jdbcTemplate;

    @PostConstruct
    public void init(){
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    /**
     * 验证用户是否存在 成功返回其权限
     * 可以根据username 实现应用成面的的用户认证 如无需认证 则可以写死password password是必须存在的
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据username 获取 user信息 返回给框架验证 这里方便测试写死

        System.out.println("loadUserByUsername="+username);
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        User userDetails = new User(username,"sunyuki@123",true,true,true,true,authorities);
        //GrantedAuthorityImpl grantedAuthority = new GrantedAuthorityImpl();
        //grantedAuthority.setAuthority("P1F1");
        //authorities.add(grantedAuthority);
        //userDetails.setAuthorities(authorities);
        return userDetails;
    }

重写WebSecurityConfigurerAdapter类 自定义过滤机制
这里如果要用授权码模式demo 请开启httpBasic


@Configuration
@EnableWebSecurity
public class OAuthWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/oauth/remove_token").permitAll()
                .anyRequest().authenticated().and().csrf().disable();
                //.httpBasic(); //开起Basic认证 授权码使用
    }
}
test

这里使用密码授权(grant_type : password refresh_token) 测试 这里的clientId password 自行在数据库里添加
这里说一下 token 和 user相关 会序列化后 以二进制的情况存入数据库、所以资源服务器 在验证的时候请注意反序列化的对象,这里都是用的spring框架的所以不会存在问题,如果要使用authorization_code demo 请允许httpBasic,client_details表里有个authorized_grant_types字段.表示client支持授权类型,如需多种请以逗号隔开 如:password,refresh_token

image
image
image
image

resource server

上面获取了token 下面说下资源服务器

//同authorization server @EnableResourceServer标示资源服务器 导入相关jar包 请参照 server 
@SpringBootApplication
@EnableResourceServer
public class Application {
    public static void main(String[] args) throws Exception {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }
}

重写ResourceServerConfigurerAdapter 定义过滤规则和tokenStore


@Configuration
public class ResourceConfig extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = "my_rest_api";

    @Autowired
    @Qualifier("tokenDataSource")
    DataSource tokenDataSource;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(tokenStore());
        resources.resourceId(RESOURCE_ID).stateless(false);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
       //http.authorizeRequests().antMatchers("/**").permitAll().anyRequest().authenticated();
        super.configure(http);
    }

    /**
     * 指定token存储的位置
     * @return
     */
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(tokenDataSource);
    }

}

测试url如:

http://secure.syk.com:8081/acct/v3/payment/pay_code/record/read/47?access_token=75949cc7-21cf-43f9-bb3f-1b6e769c7967

这里资源服务器因为公司业务 就不上传更多的资源服务器的代码

authorization server github:https://github.com/szdksconan/oauth2.0

ps:很多细节没有仔细研究 、感觉使用学习成本真不如自己写一个

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

springboot+oauth2 的相关文章

随机推荐

  • ECC椭圆曲线加解密原理详解(配图)

    ECC椭圆曲线加解密原理详解 配图 本文主要参照 ECC加密算法入门介绍及 ECC椭圆曲线详解 有具体实例 前言 椭圆曲线 ECC 加密原理跟RSA加解密原理比起来 可真是晦涩难懂 拜读了Kalafinaian的文章 ECC椭圆曲线详解 有
  • Docker进入容器命令

    docker exec it 容器名称 bash 输入 exit 退出容器
  • No module named 'tensorflow.contrib'

    命令行报错如下 import tensorflow contrib slim as slim ModuleNotFoundError No module named tensorflow contrib tensorflow 2 0以后没有
  • (Struts2学习篇) Struts2数据校验之一

    数据校验的意义 WEB数据收集的复杂性 客户数据输入的误操作 其他恶意攻击 struts2数据校验的方法 客户端校验和服务端校验 客户端校验是指 在HTML画面上自动生成JavaScript校验代码 在用户提交到服务器之前在客户端浏览器中进
  • jq校验复选框是否选择了

    jq校验复选框是否选择了 var arr sup input checkbox name custom brand ids checked each function i arr sup i this val if arr sup leng
  • remote: Support for password authentication was removed on August 13, 2021. Please use a personal ac

    报错 remote Support for password authentication was removed on August 13 2021 Please use a personal access token instead r
  • 安装Ubuntu20.04后时间不准

    安装Ubuntu20 04后时间不准 买了一台瘦客户机 原先是安装Windows操作系统的 后面安装Ubuntu20 04后导致时间一直有问题 不准 解决办法 1 安装 ntpdate sudo apt get install ntpdat
  • 超硬核!程序员10种副业赚钱之道,实现月收入增加20k!

    大家好 我是良许 经常有小伙伴问我说 良许 你的副业搞得那么溜 能不能给我们介绍一些可操作性的副业 让我们在让我们在工作之余能有另外一份收入 为了响应大家的需求 本文我就整理了一些我所知道的适合程序员的副业 向大家做一个分享 这些副业 每个
  • Node.js一些报错的解决方案

    安装 https blog csdn net qq 48485223 article details 122709354 报错1 查询版本 npm v npm WARN logfile could not create logs dir E
  • Json的格式规范

    解决报错 Resolved org springframework web HttpMediaTypeNotSupportedException Content type application x www form urlencoded
  • OCR常用公开数据集整理

    OCR常用的数据集 在这个代码仓库里 提供了常用的OCR检测和识别中的通用公开数据集的下载链接 并且提供了json标签转成 txt标签的代码和转换好的 txt标签 该项目的详细github地址如下 https github com zcsw
  • 通过Windows10上的VS Code打开远端Ubuntu上的项目操作步骤

    Ubuntu版本要求是16 04及以上版本 这里以16 04为例 在Ubuntu上安装OpenSSH server 执行 sudo apt get install openssh server 在Windows 10 1803 上安装Win
  • go-casbin学习

    casbin学习 一 背景 1 Casbin是什么 Casbin 是一个授权库 在我们希望特定用户访问特定的 对象 或实体的流程中可以使用 主题 访问类型 例如 动作 可以是 读取 写入 删除 或开发者设置的任何其他动作 这是Casbin最
  • Java开发中Word转PDF文件5种方案横向评测

    Java开发中Word转PDF文件5种方案横向评测 前段时间接了个项目 需要各种处理Word模板 转PDF 签章等等 非常头疼 其中光是一个word转PDF就折磨我好久 实现转换很简单 但是效果总是达不到满意 于是我把市面上能找到的word
  • STM32G0系列的启动配置与程序下载

    文章目录 目的 启动配置 程序下载 通过程序修改 nBOOT SEL 总结 目的 STM32G是意法半导体这两年新推出的系列芯片 相比原先的F系列的芯片有很多提升点 将来必将取代F系列芯片的地位 对于新芯片的应用来说能够正确下载与运行程序是
  • 文档服务器 件排名,十大服务器排名

    十大服务器排名 内容精选 换一换 对于公网ELB后端服务器是用于对外提供服务 ELB将访问流量分担到不同的服务器上 负载均衡器的带宽大小是根据外部访问流量访问ELB后端云服务器的带宽需求进行设置的 对于私网ELB在企业内部进行负载分担 完全
  • 【操作系统】分页储存管理方式一些计算公式以及计算例题(页表项大小,页表项,页面大小的区别)

    我在学习操作系统的时候在遇到页表项大小 页表项 页面大小的的误区 百度了好久也是很迷糊 现如今恍然大悟 今天给大家分享一下 希望大家不用迷路 之前百度到了一个这样的问题 我曾经也有过这样的问题 如图 首先我来说页表项和页面大小没有特别的关系
  • 【3D人脸】MediaPipe Face Mesh 调研

    官网效果 MediaPipe Face Mesh 不够高清 case也不够丰富 暂时看不出问题 官方AI博客 Real Time AR Self Expression with Machine Learning 没啥有价值的信息 但里面的g
  • MyBatis 分页插件pagehelper使用

    引入分页插件
  • springboot+oauth2

    SPRING BOOT OAUTH2 0 jdbc o o 搞了几天springboot的security 下的 oauth2 0 之前没接触过springboot 和security spring boot OAUTH2 0 官方文档也解