Spring-boot RestAPI 와 Spring Security OAuth2 연동(spring-boot 1.5.10 기준)
Dependency 추가
Gradle
dependencies {
...
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.security.oauth:spring-security-oauth2')
...
}
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
인증URL 설정
ResourceServerConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable().and()
.authorizeRequests()
.antMatchers("/swagger-resources/**","/swagger-ui.html",
"/v2/api-docs", "/webjars/**").permitAll() // Swagger Support
.antMatchers("/", "/api/public-key", "/error").permitAll()
.anyRequest().authenticated()
;
}
}
@EnableResourceServer 어노테이션을 추가한 클래스가 만들어지면 기본적으로 모든요청에 대해 인증을 필요로하게 된다.
특정 url에 대해서 인증을 필요로하지 않을 경우 위와같이하면 permitAll 을 제외한 모든 요청에 인증이 필요하다는 설정이고
또는 특정 url에 대해서만 인증이 필요하다면 permitAll과 authenticated 호출하는 부분의 순서를 바꿔주면 된다.
properties 추가
application.yml
security.oauth2:
client.client-id: foo
client.client-secret: bar
resource.token-info-uri: http://192.168.88.133:8780/oauth/check_token
auth-server-uri: http://192.168.88.133:8780
token요청 및 검증을 위해 인증서버의 tokin-info-uri와 client id/secret 등 설정이 추가되어야함
Swagger 관련 설정
SwaggerConfig.java
@Value("${security.oauth2.auth-server-uri}")
private String authServer;
@Value("${security.oauth2.client.client-id}")
private String clientId;
@Value("${security.oauth2.client.client-secret}")
private String clientSecret;
@Bean
public Docket api(ServletContext servletContext) {
return new Docket(DocumentationType.SWAGGER_2)
....
.securitySchemes(Arrays.asList(securityScheme()))
.securityContexts(securityContexts())
....
;
}
@Bean
public SecurityConfiguration security() {
return SecurityConfigurationBuilder.builder()
.clientId(clientId)
.clientSecret(clientSecret)
.scopeSeparator(",")
.useBasicAuthenticationWithAccessCodeGrant(true)
.build();
}
private SecurityScheme securityScheme() {
GrantType grantType = new AuthorizationCodeGrantBuilder()
.tokenEndpoint(new TokenEndpoint(authServer + "/oauth/token", "oauthtoken"))
.tokenRequestEndpoint(
new TokenRequestEndpoint(authServer + "/oauth/authorize", clientId, clientSecret))
.build();
SecurityScheme oauth = new OAuthBuilder().name("spring_oauth")
.grantTypes(Arrays.asList(grantType))
.scopes(Arrays.asList(scopes()))
.build();
return oauth;
}
private AuthorizationScope[] scopes() {
AuthorizationScope[] scopes = {
new AuthorizationScope("read", "for read operations"),
new AuthorizationScope("write", "for write operations")
};
return scopes;
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContexts = new ArrayList<>();
String paths[] = {
"/api/dashboard.*",
"/api/metric-statistics.*"
};
for (String path: paths) {
securityContexts.add(SecurityContext.builder()
.securityReferences(Arrays.asList(new SecurityReference("spring_oauth", scopes())))
.forPaths(PathSelectors.regex(path))
.build());
}
return securityContexts;
}
Oauth서버의 해당클라이언트에 허용가능한 scope와 인증이 필요한 API Path등을 Swagger에 적용한다