Configure JWT Authentication for OpenAPIλ₯Ό μ°Έκ³ ν•˜λ©΄ SpringDoc UIλ₯Ό μ‚¬μš©ν•  λ•Œ JWT 인증을 μœ„ν•΄ Bearer μŠ€ν‚€λ§ˆ μœ ν˜•μ„ ꡬ성할 수 μžˆμŒμ„ μ‰½κ²Œ μ•Œ 수 μžˆλ‹€. κ·ΈλŸ¬λ‚˜, Bearer와 같은 인증 λ°©μ‹μ˜ 경우 OAuth μ™€λŠ” λ‹€λ₯΄κ²Œ 기본값을 μ μš©ν•  수 μžˆλŠ” λ°©μ•ˆμ΄ μ—†λ‹€. μŠ€μ›¨κ±° λ¬Έμ„œμ—μ„œ APIλ₯Ό ν˜ΈμΆœν•΄λ³΄κ³  싢은 경우 λŒ€λΆ€λΆ„ μŠ€ν”„λ§ μ‹œνλ¦¬ν‹°μ—μ„œ μ œκ³΅ν•˜λŠ” HTTP κΈ°λ³Έ μΈμ¦μ΄λ‚˜ 폼 λ‘œκ·ΈμΈμ„ ν•˜μ§€ λͺ»ν•˜λ„둝 λΉ„ν™œμ„±ν™”ν•˜κΈ° λ•Œλ¬Έμ— μ‚¬μš©μž λ‘œκ·ΈμΈμ„ μˆ˜ν–‰ν•  수 μžˆλŠ” μ—”λ“œν¬μΈνŠΈλ₯Ό λ§Œλ“€μ–΄μ„œ λ¬Έμ„œμ— λ…ΈμΆœν•˜μ—¬ 토큰을 λ°œκΈ‰ν•  수 μžˆλ„λ‘ ν•΄μ•Όν•œλ‹€.

기본적으둜 ν”„λ‘œμ νŠΈ 개발 μ‹œ Bearer 인증 μ‹œ Input λ°•μŠ€μ— 기본값을 λ„£μ–΄λ‘˜ λ°©μ•ˆμ€ μ—†μŠ΅λ‹ˆλ‹€.

SecurityScheme

@SecurityScheme(
    name = "Bearer Authentication",
    type = SecuritySchemeType.HTTP,
    in = SecuritySchemeIn.HEADER,
    bearerFormat = "JWT",
    scheme = "bearer"
)
@Configuration
public class DocsConfig {}

Configure JWT Authentication for OpenAPI

μœ„ λ§ν¬μ—μ„œ Bearer Authentication 에 λŒ€ν•œ 이미지λ₯Ό 잘 μ‚΄νŽ΄λ³΄λ©΄ Description 이 ν‘œμ‹œλ˜λŠ” κ±Έ 확인할 수 μžˆλ‹€. 인증 방법에 λŒ€ν•œ μ„€λͺ…을 μ œκ³΅ν•˜λŠ” λΆ€λΆ„μ΄μ§€λ§Œ 일반 ν…μŠ€νŠΈ 뿐만 μ•„λ‹ˆλΌ HTML νƒœκ·Έκ°€ κ°€λŠ₯ν•œ κ²ƒμœΌλ‘œ 보인닀. λ³Έ κΈ€μ—μ„œλŠ” 이것을 μ΄μš©ν•΄μ„œ 개발 ν™˜κ²½μ—μ„œλŠ” ν…ŒμŠ€νŠΈ μ‚¬μš©μžμ— λŒ€ν•œ 이름과 토큰이 ν‘œμ‹œλ  수 μžˆλ„λ‘ ν•  μ˜ˆμ •μ΄λ‹€.

Customize SecurityScheme

@SecurityScheme μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ κΈ€λ‘œλ²Œ 인증에 λŒ€ν•œ 섀정을 κ΅¬μ„±ν–ˆλ‹€λ©΄ OpenAPIλ₯Ό 빈으둜 λ“±λ‘ν•˜λŠ” κ΅¬μ„±μœΌλ‘œ 변경이 ν•„μš”ν•˜λ‹€.
μ•„λž˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ†μ„±μœΌλ‘œ λ“±λ‘λœ μ‚¬μš©μž 토큰 정보λ₯Ό Description μ˜μ—­μ— ν‘œμ‹œλ  수 μžˆλ„λ‘ κ΅¬ν˜„ν•œ μ˜ˆμ œμ΄λ‹€.

@Configuration
public class DocsConfig {
    public static final String DEFAULT_AUTH = "JWT Authentication";

    @Bean
    public OpenAPI openAPI(BearerTokenProperties bearerTokenProperties) {
        SecurityRequirement securityRequirement = new SecurityRequirement().addList(DEFAULT_AUTH);
        SecurityScheme securityScheme = new SecurityScheme()
            .name(DEFAULT_AUTH)
            .type(SecurityScheme.Type.HTTP)
            .in(SecurityScheme.In.HEADER)
            .scheme("bearer")
            .bearerFormat("JWT");

        if (bearerTokenProperties.isEnabled() && !bearerTokenProperties.getTokens().isEmpty()) {
            List<BearerTokenProperties.BearerToken> tokens = bearerTokenProperties.getTokens();
            // NOTE: It is rendered as a markdown.
            String description = tokens.stream()
                .map(item -> String.format("**%s** %s", item.getName(), item.getToken()))
                .collect(Collectors.joining("\n\n"));
            securityScheme.description(description);
        }

        return new OpenAPI()
            .addSecurityItem(securityRequirement)
            .components(new Components()
                .addSecuritySchemes(DEFAULT_AUTH, securityScheme));
    }
}
@Getter
@ConstructorBinding
@RequiredArgsConstructor
@ConfigurationProperties("springdoc.bearer")
public class BearerTokenProperties {
    private final boolean enabled;
    private final List<BearerToken> tokens;

    @Getter
    @RequiredArgsConstructor
    public static class BearerToken {
        private final String name;
        private final String token;
    }
}
application-dev.yml
springdoc: bearer: enabled: on tokens: - name: Default token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - name: User2 token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

참고둜 μœ„ 예제 μ½”λ“œλ₯Ό 보면 λ§ˆν¬λ‹€μš΄ ν˜•μ‹μœΌλ‘œ λ¬Έμžμ—΄μ„ κ΅¬μ„±ν–ˆλŠ”λ° 개발자 λ„κ΅¬λ‘œ Description μ˜μ—­μ„ μ‚΄νŽ΄λ³΄λ‹ˆ λ§ˆν¬λ‹€μš΄ λ Œλ”λ§μœΌλ‘œ 되고 μžˆμ–΄μ„œ ꡳ이 HTML νƒœκ·Έλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. λ§ˆν¬λ‹€μš΄μ— μ΅μˆ™ν•˜μ§€ μ•ŠλŠ” 개발자라면 일반 HTML νƒœκ·Έλ‘œ λ§Œλ“œμ‹œλ©΄ λ©λ‹ˆλ‹€.