springboot+oauth2

1 篇文章 0 订阅
1 篇文章 0 订阅
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:很多细节没有仔细研究 、感觉使用学习成本真不如自己写一个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值