OAuth 보안: 클라이언트 정보 데이터베이스 저장 방식

이전 모든 설정에서 클라이언트 정보와 인가 코드 모드의 인가 코드는 여전히 데이터베이스에 저장되어 있었습니다. 이는 후기 확장에 불리하므로, 실제 운영 환경에서는 일반적으로 데이터베이스에 저장하는 방식을 사용합니다.

테이블 생성

먼저 OAuth 공식 문서에 제공된 데이터베이스 테이블 생성 예시에 따라 관련 테이블을 생성합니다. 여기서는 oauth_client_details와 oauth_code 테이블만 필요합니다.

############################## oauth_client_details #############################
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details`(
`client_id` varchar(255)  CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '클라이언트 식별자',
`resource_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '접근 자원 목록',
`client_secret` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '클라이언트 비밀키',
`scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authorized_grant_types` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`web_server_redirect_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authorities` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`access_token_validity` int(11) NULL DEFAULT NULL,
`refresh_token_validity` int(11) NULL DEFAULT NULL,
`additional_information` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0),
`archived` tinyint(4) NULL DEFAULT NULL,
`trusted` tinyint(4) NULL DEFAULT NULL,
`autoapprove` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`client_id`) USING BTREE
)ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '접속 클라이언트 정보'
ROW_FORMAT = Dynamic;

INSERT INTO `oauth_client_details` VALUES ('sample_client', 'resource1',
'$2a$10$NlBC84MVb7F95EXYTXwLneXgCca6/GipyWR5NHm8K0203bSQMLpvm', 'all',
'client_credentials,password,authorization_code,implicit,refresh_token','http://www.example.com',
NULL,7200,259200,NULL,'2023-06-02 16:04:28',0,0,'false');

############################## oauth_code #################################
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code`(
`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authentication` blob NULL,
INDEX `code_index`(`code`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

여기서 client_secret은 암호화된 비밀키입니다.

참고: 공식 문서에 제공된 표준 SQL 테이블 생성 문장은 HSQL 데이터베이스를 기준으로 하며, 실제 사용 시 데이터베이스 유형에 맞게 수정해야 합니다.

인증 서버 수정

  1. 클라이언트 구성 수정
@Resource
private DataSource dataSource;

// 새로 추가
@Bean
public ClientDetailsService customClientDetailsService(DataSource dataSource) {
    ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
    ((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(passwordEncoder());
    return clientDetailsService;
}

// 수정
@Override
public void configure(ClientDetailsServiceConfigurer clients)throws Exception{
    clients.withClientDetails(customClientDetailsService); 
}

동시에 jdbc 의존성을 추가해야 합니다:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

  1. 인가 코드 저장 구성 수정
// 수정
@Bean
public AuthorizationCodeServices authCodeServices(DataSource dataSource) { 
    // 인가 코드 모드의 인가 코드 저장 방식 설정
    return new JdbcAuthorizationCodeServices(dataSource);
}

확장 기능

JdbcClientDetailsService의 소스 코드를 살펴보겠습니다.

public JdbcClientDetailsService(DataSource dataSource) {
    this.updateClientDetailsSql = DEFAULT_UPDATE_STATEMENT;
    this.updateClientSecretSql = "update oauth_client_details set client_secret = ? where client_id = ?";
    this.insertClientDetailsSql = "insert into oauth_client_details (client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove, client_id) values (?,?,?,?,?,?,?,?,?,?,?)";
    this.selectClientDetailsSql = "select client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove from oauth_client_details where client_id = ?";
    this.passwordEncoder = NoOpPasswordEncoder.getInstance();
    Assert.notNull(dataSource, "DataSource required");
    this.jdbcTemplate = new JdbcTemplate(dataSource);
    this.listFactory = new DefaultJdbcListFactory(new NamedParameterJdbcTemplate(this.jdbcTemplate));
}

위 코드를 통해 소스 코드에 이미 우리를 위한 CRUD 기능이 구현되어 있음을 알 수 있습니다. 이는 사용하는 데이터베이스 SQL 형식이 지원되지 않는 경우 토큰을 얻을 수 없음을 의미합니다. 이 문제를 어떻게 해결할 수 있을까요? 공식적으로도 이에 대한 해결책을 제공합니다:

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
    jdbcClientDetailsService.setFindClientDetailsSql("");
    clients.withClientDetails(jdbcClientDetailsService);
}

클라이언트 정보를 구성할 때 기본값을 대체하기 위해 사용자 정의 SQL 문을 사용할 수 있습니다.

태그: OAuth 보안 인증 클라이언트 구성 데이터베이스 저장 스프링 시큐리티

6월 30일 01:38에 게시됨