spring-security-oauth 심층 분석 - 2

2016. 3. 14. 18:27Java/Spring Framework

에 있는 내용들을 설명 했고, 이젠 차근차근 하나씩 예제 내용을 기반으로 만들어 본다.



1. pom.xml

Spring.io로 프로젝트를 생성하도록 하겠습니다. Spring Boot를 사용한다는 뜻이죠,
web , actuator, security,  jpa, h2 , lombok 정도 설정하고,
oauth2 는 별도로 추가했습니다... 그럼 아래와 같이 되겠죠

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.example</groupId>
   <artifactId>demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>OAuth2JPA</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.3.3.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-security</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.security.oauth</groupId>
         <artifactId>spring-security-oauth2</artifactId>
      </dependency>
      <dependency>
         <groupId>com.h2database</groupId>
         <artifactId>h2</artifactId>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.16.6</version>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
   
</project>


2. Application.yml 

Resource 폴더에는 Thymeleaf 를 사용할수 있도록 static,templates 그리고 기본적으로 application.properties가 들어 있는데, 과감히 삭제합니다.
그리고 application.yml 를 생성해서 추가합니다. 전 향후에는 properties 보단, 이젠 .yml 를 사용할 예정입니다. 
 위에서 말한 내용들이 그대로 들어가 있습니다. 

spring:
     application:
         name : jpa
management :
    context_path :  /admin
security :
    user : 
        password : password
logging : 
    level : 
       # org.springframework.security : DEBUG

위에 pom 설정중에 actuator를 설정했습니다.
그리고 yml 상에 manage 의  context_path 를 /admin 으로 했습니다.
security에 password를 password 라고 했습니다.  이것이 어떤 기능을 하는지 이제 천천히 보도록 합시다.


3. Application.java

저는 OAuth2Jpa 라고 프로젝트를 만들어 놓고 보니, Application 이름이 바뀌긴 했지만, 뭐 걱정 없습니다.
이 상태에서 아무것도 등록을 하지 않았지만,  Application를 기동해 봅니다.
위의 기본적인 설정후에 Console 로그를 보도록 하겠습니다.

2016-03-11 12:05:11.764  INFO 6436 --- [           main] com.example.OAuth2JpaApplication         : Starting OAuth2JpaApplication on USER-PC with PID 6436 (C:\Users\USER\IdeaProjects\OAuth2JPA\target\classes started by USER in C:\Users\USER\IdeaProjects\OAuth2JPA)
2016-03-11 12:05:11.778  INFO 6436 --- [           main] com.example.OAuth2JpaApplication         : No active profile set, falling back to default profiles: default
2016-03-11 12:05:11.912  INFO 6436 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@75f32542: startup date [Fri Mar 11 12:05:11 KST 2016]; root of context hierarchy

내 컴퓨터의 PID가 6436 으로 가동을 시작했다라는 로그 와 active 한 profile 세팅이 없다라는 내용 따라서, default 프로필로 설정했다는 이군요.
시작날짜와 함께 어노테이션 설정을 보는 것 같습니다. 

2016-03-11 12:05:13.552  INFO 6436 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2016-03-11 12:05:13.592  INFO 6436 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'ignoredPathsWebSecurityConfigurerAdapter' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.security.SpringBootWebSecurityConfiguration; factoryMethodName=ignoredPathsWebSecurityConfigurerAdapter; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration; factoryMethodName=ignoredPathsWebSecurityConfigurerAdapter; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.class]]
2016-03-11 12:05:14.159  INFO 6436 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [class org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$572ed2a] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

"beanNameViewResolver" 는 주로 커스텀 뷰로 사용하며, 컨트롤러에서 리턴받은 뷰의 이름과 빈으로 등록되어 있는 id의 값이 일치하는 것을 찾아서 실행 합니다...  beanNameViewResolver 빈을 위해 빈정의를 오버라이딩 하는 것입니다.
이따, 추가를 해보고 뭐가 변경되었는지 비교를 하면 더 이해하기 쉬울것 같습니다.
"ignoredPathsWebSecurityConfigurerAdapter" 는 설명을 찾기가 힘들긴 한데, 말 그대로 해석을 하면 웹 security 설정상에 무시되는 경로들을 찾는 것 같습니다. (예를 들어 css,image,js 등과 같은 명확하게 무시되는 경로들을 제외하는 것 같습니다. By default, everything is secured with HTTP Basic authentication except the explicitly ignored paths(defaults to /css/**,/js/**,/images/**,/**/favicon.ico. ))
"ProxyTransactionManagementConfiguration" 요건 proxy-based annotation-driven transaction management를 필수적으로 가능하게 하는  스프링 구조를 등록하는 설정 클래스랍니다. 

2016-03-11 12:05:14.734  INFO 6436 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2016-03-11 12:05:14.750  INFO 6436 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2016-03-11 12:05:14.753  INFO 6436 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.32
2016-03-11 12:05:14.898  INFO 6436 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2016-03-11 12:05:14.898  INFO 6436 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2989 ms

드디어 내장 톰캣이 시작되었습니다.
서블릿 엔진이 시작하고, Spring embedded WebApplicationContext를 초기화 합니다. 
Root WebApplicationContext 초기화를 완료하는데, 대략 3초 걸렸네요

2016-03-11 12:05:15.331  INFO 6436 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'metricFilter' to: [/*]
2016-03-11 12:05:15.331  INFO 6436 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-03-11 12:05:15.331  INFO 6436 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-03-11 12:05:15.332  INFO 6436 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-03-11 12:05:15.332  INFO 6436 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'requestContextFilter' to: [/*]
2016-03-11 12:05:15.333  INFO 6436 --- [ost-startStop-1] .e.DelegatingFilterProxyRegistrationBean : Mapping filter: 'springSecurityFilterChain' to: [/*]
2016-03-11 12:05:15.333  INFO 6436 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'webRequestLoggingFilter' to: [/*]
2016-03-11 12:05:15.333  INFO 6436 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'applicationContextIdFilter' to: [/*]
2016-03-11 12:05:15.334  INFO 6436 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

필터를 매핑하기 시작합니다... 두두두두

2016-03-11 12:05:15.780  INFO 6436 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/css/**'], Ant [pattern='/js/**'], Ant [pattern='/images/**'], Ant [pattern='/**/favicon.ico'], Ant [pattern='/error']]], []

필터 체인을 생성합니다. 특이한건 리소스쪽은 제외하는 것 같네요

2016-03-11 12:05:15.849  INFO 6436 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/admin/**'], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4f38f00b, org.springframework.security.web.context.SecurityContextPersistenceFilter@47af0640, org.springframework.security.web.header.HeaderWriterFilter@70eefdc6, org.springframework.security.web.authentication.logout.LogoutFilter@a3e5826, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@eb905c, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2d351c84, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@355cf727, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@130df0c0, org.springframework.security.web.session.SessionManagementFilter@7b9a0793, org.springframework.security.web.access.ExceptionTranslationFilter@116853f8, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@36ccf2dd]

필터 체인을 생성합니다. /admin/** 에다가요.. 

2016-03-11 12:05:15.853  INFO 6436 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/**']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@e5b9d9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@56446b4a, org.springframework.security.web.header.HeaderWriterFilter@10b916df, org.springframework.security.web.authentication.logout.LogoutFilter@2645c5f1, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@532ee448, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@43a710a3, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1b70f9e6, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1fa36a79, org.springframework.security.web.session.SessionManagementFilter@f3657de, org.springframework.security.web.access.ExceptionTranslationFilter@484bb7a6, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@189e39fb]

필터 체인을 생성합니다. 전체에 .. 

2016-03-11 12:05:16.231  INFO 6436 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2016-03-11 12:05:16.244  INFO 6436 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
2016-03-11 12:05:16.410  INFO 6436 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {4.3.11.Final}
2016-03-11 12:05:16.412  INFO 6436 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2016-03-11 12:05:16.414  INFO 6436 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2016-03-11 12:05:16.729  INFO 6436 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
2016-03-11 12:05:16.805  INFO 6436 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2016-03-11 12:05:16.853  INFO 6436 --- [           main] o.h.h.i.ast.ASTQueryTranslatorFactory    : HHH000397: Using ASTQueryTranslatorFactory
2016-03-11 12:05:16.984  INFO 6436 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000227: Running hbm2ddl schema export
2016-03-11 12:05:16.986  INFO 6436 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000230: Schema export complete

이 부분은 JPA 설정이 초기화 되는 부분입니다.

2016-03-11 12:05:17.186  INFO 6436 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@75f32542: startup date [Fri Mar 11 12:05:11 KST 2016]; root of context hierarchy
2016-03-11 12:05:17.261  INFO 6436 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2016-03-11 12:05:17.262  INFO 6436 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)

RequestMappingHandlerAdapter 설정 , 에러 설정

2016-03-11 12:05:17.286  INFO 6436 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-03-11 12:05:17.287  INFO 6436 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-03-11 12:05:17.317  INFO 6436 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

URL 매핑

2016-03-11 12:05:17.665  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/beans || /admin/beans.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-03-11 12:05:17.665  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/trace || /admin/trace.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-03-11 12:05:17.665  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/autoconfig || /admin/autoconfig.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-03-11 12:05:17.666  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/metrics/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2016-03-11 12:05:17.666  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/metrics || /admin/metrics.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-03-11 12:05:17.666  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/mappings || /admin/mappings.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-03-11 12:05:17.669  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/dump || /admin/dump.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-03-11 12:05:17.670  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/configprops || /admin/configprops.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-03-11 12:05:17.670  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/env/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
2016-03-11 12:05:17.670  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/env || /admin/env.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-03-11 12:05:17.671  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/health || /admin/health.json],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(java.security.Principal)
2016-03-11 12:05:17.671  INFO 6436 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/admin/info || /admin/info.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()

요것이 actuator 상에서 제공하는 URL 이네

2016-03-11 12:05:17.779  INFO 6436 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2016-03-11 12:05:17.787  INFO 6436 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2016-03-11 12:05:17.904  INFO 6436 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2016-03-11 12:05:17.909  INFO 6436 --- [           main] com.example.OAuth2JpaApplication         : Started OAuth2JpaApplication in 6.674 seconds (JVM running for 7.631)
2016-03-11 12:05:58.724  INFO 6436 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2016-03-11 12:05:58.724  INFO 6436 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2016-03-11 12:05:58.742  INFO 6436 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 18 ms

뭐.. 그래서 tomcat이 8080 포트 상에서 시작되고, 어플리케이션이 시작되고, dispatcherServle이 초기화 되고, FrameworkServlet 인 'dispatcherServlet"이 시작되고, 초기화가 완료 됩니다.

그리고 나서 위에 매핑된 URL 몇개를 입력 해보면 , http://localhost:8080/admin/autoconfig 이라고 입력하면, 
어떠한 설정을 하지 않으면, httpBasic 모드로 인증 요청 로그인 창이 뜨게 됩니다. 
그럼 위에 입력한 패스워드를 입력합니다. username 은 그냥 user 입니다. 
그럼 어마 무시한 무언가가... 찍혀져서 나올 것입니다. 간단히 아래 것으로 비교 해보죠 . 

http://localhost:8080/admin/health  (로그인 전)
{"status":"UP"}

http://localhost:8080/admin/health  (로그인 후)
{"status":"UP","diskSpace":{"status":"UP","total":249585389568,"free":155453665280,"threshold":10485760},"db":{"status":"UP","database":"H2","hello":1}}

/admin/health 는 로그인 여부와 상관없이 값이 나오는데, 제공되는 값에 제약이 있네요.

만약에 postman 같은 것으로 테스트를 해보면 좀 더 명확합니다.
http://localhost:8080/admin/configprops
{
  "timestamp": 1457682507373,
  "status": 401,
  "error": "Unauthorized",
  "message": "Full authentication is required to access this resource",
  "path": "/admin/configprops"
}


4. EnableAutorizationServer 



그럼 이제 부터 드뎌 @EnableAuthorizationServer 설정 작업 들어 갑니다.



@SpringBootApplication
public class OAuth2JpaApplication {

   public static void main(String[] args) {
      SpringApplication.run(OAuth2JpaApplication.class, args);
   }


   @Configuration
   @EnableAuthorizationServer
   protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
      @Autowired
      private AuthenticationManager authenticationManager;

      @Override
      public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
         endpoints.authenticationManager(authenticationManager);
      }

      @Override
      public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
         security.checkTokenAccess("isAuthenticated()");
      }

      @Override
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
         // @formatter:off
         clients.inMemory()
               .withClient("my-trusted-client")
               .authorizedGrantTypes("password""authorization_code""refresh_token""implicit")
               .authorities("ROLE_CLIENT""ROLE_TRUSTED_CLIENT")
               .scopes("read""write""trust")
               .resourceIds("oauth2-resource")
               .accessTokenValiditySeconds(600)
               .and()
               .withClient("my-client-with-registered-redirect")
               .authorizedGrantTypes("authorization_code")
               .authorities("ROLE_CLIENT")
               .scopes("read""trust")
               .resourceIds("oauth2-resource")
               .redirectUris("http://anywhere?key=value")
               .and()
               .withClient("my-client-with-secret")
               .authorizedGrantTypes("client_credentials""password")
               .authorities("ROLE_CLIENT")
               .scopes("read")
               .resourceIds("oauth2-resource")
               .secret("secret");
         // @formatter:on
      }
   }

}


위와 같이  @EnableAuthorizationServer 을 추가하면서 생성되는 것이 바로, 아래 매핑부분입니다. 

2016-03-14 10:30:07.364 DEBUG 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking for request mappings in application context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2928854b: startup date [Mon Mar 14 10:30:03 KST 2016]; root of context hierarchy
2016-03-14 10:30:07.378 DEBUG 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : 1 request handler methods found on class org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint: {public java.util.Map org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint.checkToken(java.lang.String)={[/oauth/check_token]}}
2016-03-14 10:30:07.380  INFO 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/check_token]}" onto public java.util.Map<java.lang.String, ?> org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint.checkToken(java.lang.String)
2016-03-14 10:30:07.384 DEBUG 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : 1 request handler methods found on class org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint: {public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint.getAccessConfirmation(java.util.Map,javax.servlet.http.HttpServletRequest) throws java.lang.Exception={[/oauth/confirm_access]}}
2016-03-14 10:30:07.385  INFO 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/confirm_access]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint.getAccessConfirmation(java.util.Map<java.lang.String, java.lang.Object>,javax.servlet.http.HttpServletRequest) throws java.lang.Exception
2016-03-14 10:30:07.385 DEBUG 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : 1 request handler methods found on class org.springframework.security.oauth2.provider.endpoint.WhitelabelErrorEndpoint: {public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelErrorEndpoint.handleError(javax.servlet.http.HttpServletRequest)={[/oauth/error]}}
2016-03-14 10:30:07.385  INFO 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/error]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelErrorEndpoint.handleError(javax.servlet.http.HttpServletRequest)
2016-03-14 10:30:07.395 DEBUG 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : 2 request handler methods found on class org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint: {public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map,java.util.Map,org.springframework.web.bind.support.SessionStatus,java.security.Principal)={[/oauth/authorize]}, public org.springframework.web.servlet.View org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.approveOrDeny(java.util.Map,java.util.Map,org.springframework.web.bind.support.SessionStatus,java.security.Principal)={[/oauth/authorize],methods=[POST],params=[user_oauth_approval]}}
2016-03-14 10:30:07.395  INFO 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/authorize]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.String>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
2016-03-14 10:30:07.396  INFO 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/authorize],methods=[POST],params=[user_oauth_approval]}" onto public org.springframework.web.servlet.View org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.approveOrDeny(java.util.Map<java.lang.String, java.lang.String>,java.util.Map<java.lang.String, ?>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
2016-03-14 10:30:07.397 DEBUG 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : 2 request handler methods found on class org.springframework.security.oauth2.provider.endpoint.TokenEndpoint: {public org.springframework.http.ResponseEntity org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.getAccessToken(java.security.Principal,java.util.Map) throws org.springframework.web.HttpRequestMethodNotSupportedException={[/oauth/token],methods=[GET]}, public org.springframework.http.ResponseEntity org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map) throws org.springframework.web.HttpRequestMethodNotSupportedException={[/oauth/token],methods=[POST]}}
2016-03-14 10:30:07.398  INFO 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/token],methods=[GET]}" onto public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.getAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException
2016-03-14 10:30:07.399  INFO 8336 --- [ost-startStop-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/token],methods=[POST]}" onto public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException

그리고 난 뒤에 필터 체인을 생성해 주네요. 

2016-03-14 10:30:07.527 DEBUG 8336 --- [ost-startStop-1] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'fullyAuthenticated', for Ant [pattern='/oauth/token']
2016-03-14 10:30:07.531 DEBUG 8336 --- [ost-startStop-1] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'denyAll()', for Ant [pattern='/oauth/token_key']
2016-03-14 10:30:07.532 DEBUG 8336 --- [ost-startStop-1] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'isAuthenticated()', for Ant [pattern='/oauth/check_token']
2016-03-14 10:30:07.544 DEBUG 8336 --- [ost-startStop-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes
2016-03-14 10:30:07.545 DEBUG 8336 --- [ost-startStop-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes
2016-03-14 10:30:07.556  INFO 8336 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/oauth/token'], Ant [pattern='/oauth/token_key'], Ant [pattern='/oauth/check_token']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5805eda6, org.springframework.security.web.context.SecurityContextPersistenceFilter@43ee2539, org.springframework.security.web.header.HeaderWriterFilter@54f84219, org.springframework.security.web.authentication.logout.LogoutFilter@18d26e0, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@39b763a3, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@d70330f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@699a8cab, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5a2d277e, org.springframework.security.web.session.SessionManagementFilter@4b2309d1, org.springframework.security.web.access.ExceptionTranslationFilter@2b94a858, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@31e59af5]
2016-03-14 10:30:07.563 DEBUG 8336 --- [ost-startStop-1] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration$LazyEndpointPathRequestMatcher@aadf10a
2016-03-14 10:30:07.563 DEBUG 8336 --- [ost-startStop-1] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'hasRole('ROLE_ADMIN')', for org.springframework.security.web.util.matcher.AnyRequestMatcher@1
2016-03-14 10:30:07.565 DEBUG 8336 --- [ost-startStop-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes
2016-03-14 10:30:07.565 DEBUG 8336 --- [ost-startStop-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes


4-1. Authentication Type

이 상태에서 테스트를 진행해봅니다.
이번에는 인증서버에서 토큰을 발급을 받는데, 방식은 아래와 같은 clientid,client-secret 로만 받는 방법 입니다.

curl -H "Accept: application/json" my-client-with-secret:secret@localhost:8080/oauth/token -d grant_type=client_credentials
==>  {"access_token":"7c4e47be-9080-4cf6-9f64-d5d3744ca16d","token_type":"bearer","expires_in":43199,"scope":"read"}%


위의 설정중에는 여러 형태가 있는데,  3번째 방법으로 진행했고, 첫번째 방법으로 진행 할 경우에는, 아래와 같이 진행 하면 됩니다.

curl -u my-trusted-client: http://localhost:8080/oauth/token -d "grant_type=password&username=user&password=password" 
==>{"access_token":"05e90f94-7426-4ad8-b6a9-fb10f4642824","token_type":"bearer","refresh_token":"b2a691d3-ffef-4739-9796-95f2b87b1258","expires_in":599,"scope":"read write trust"}%

그럼 이번에는 두번째 방법도 알아야 겠습니다. 
my-client-with-registered-redirect 는 AccessToken 발급을 받기 위해 권한 승인후 코드를 가져오는 과정이 필요하다.
http://localhost:8080/oauth/authorize?client_id=my-client-with-registered-redirect&response_type=code




http://anywhere/?key=value&code=xBTm8g 라고 리다이렉트 되고 난 뒤에 code 값이 나오는데 그 코드 값을 

curl -u my-client-with-registered-redirect: http://localhost:8080/oauth/token -d "grant_type=authorization_code&code=xBTm8g"
==>{"access_token":"6d5e3474-94ca-47e3-9154-65a054c7163d","token_type":"bearer","expires_in":43199,"scope":"trust read"}%


이렇게 나온다.... 좋다..  그 다음에 테스트는 간단합니다.
Header 에 Authorization : bear 7c4e47be-9080-4cf6-9f64-d5d3744ca16d 으로 요청하면 됩니다.
어라? 이게 나오네.. 아직까지 권한인증이 안되네요... 

{
  "timestamp": 1457682851316,
  "status": 401,
  "error": "Unauthorized",
  "message": "Full authentication is required to access this resource",
  "path": "/"
}

에러 메세지는 Full authentication은 이 리소스에 접근하기 위해서는 필요하다라고 하네요.
다시 말하자면,  @EnableResourceServer 설정을 안해줘서 그렇답니다.
이제 해보죠 ... 오... 뭔가 다른 값이 리턴되었네요... 토큰이 잘못 되었다는... 좋습니다.

5. EnableResourceServer

그럼 기존과 다른 내용이 나오겠죠

2016-03-14 10:44:57.975 DEBUG 3976 --- [ost-startStop-1] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'authenticated', for org.springframework.security.web.util.matcher.AnyRequestMatcher@1

웹 접속 컨트롤 표현인 'authenticated' 이 추가 되었다고 합니다.

2016-03-14 10:44:57.976  INFO 3976 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration$NotOAuthRequestMatcher@76845965, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5ae6e4a8, org.springframework.security.web.context.SecurityContextPersistenceFilter@167902a9, org.springframework.security.web.header.HeaderWriterFilter@2764ffe7, org.springframework.security.web.authentication.logout.LogoutFilter@a16d85e, org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter@5f37e19e, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@338805c1, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@33934f90, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4fb1a2f0, org.springframework.security.web.session.SessionManagementFilter@3c90a591, org.springframework.security.web.access.ExceptionTranslationFilter@5a5ff166, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@12318730]
2016-03-14 10:44:57.985 DEBUG 3976 --- [ost-startStop-1] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration$LazyEndpointPathRequestMatcher@b7dc6d3
2016-03-14 10:44:57.985 DEBUG 3976 --- [ost-startStop-1] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'hasRole('ROLE_ADMIN')', for org.springframework.security.web.util.matcher.AnyRequestMatcher@1
2016-03-14 10:44:57.986 DEBUG 3976 --- [ost-startStop-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes
2016-03-14 10:44:57.987 DEBUG 3976 --- [ost-startStop-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes

추가적인 필터 체인이 들어갑니다. 
간단히....Hello world 나오도록 만들고, 만들어 보고, 위와 같은 테스트!!!

@RestController
public class HomeController {

    @RequestMapping("/")
    public String home() {
        return "Hello World";
    }
}


2016-03-11 16:30:48.802  INFO 13512 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.example.HomeController.home()


자~~~~~~~~알 나옵니다.


여기 까지가... 그냥 노멀한 in-memory 테스트 입니다. 

6. Tokenstore with DB 

이번에는 DB에 token을 저장하도록 합니다. 


@RestController
@EnableAutoConfiguration
@SpringBootApplication
public class Application{

    @Autowired
    private DataSource dataSource;

    @Autowired
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        // @formatter:off
        auth.jdbcAuthentication().dataSource(dataSource).withUser("hellowd")
                .password("testpass").roles("USER");
        // @formatter:on
    }

그다음 ResourceServer 설정....


@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;

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

    @Override
    public void configure(HttpSecurity http) throws Exception {
        //jdbc:h2:mem:testdb 헤더 충돌시 설정
        http.headers().frameOptions().disable();
        http.authorizeRequests()
                .antMatchers("/h2-console""/h2-console/**").permitAll();
        http.authorizeRequests()
                .antMatchers("/""/admin/**").access("#oauth2.hasScope('read')")
                .anyRequest().authenticated();
       // http.authorizeRequests().anyRequest().authenticated();
    }
}

마무리는 역시 




@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager auth;

    @Autowired
    private DataSource dataSource;

    private BCryptPasswordEncoder passwordEncoder new BCryptPasswordEncoder();

    @Bean
    public JdbcTokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Bean
    protected AuthorizationCodeServices authorizationCodeServices() {
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security)
            throws Exception {
        security.passwordEncoder(passwordEncoder);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
        endpoints.authorizationCodeServices(authorizationCodeServices())
                .authenticationManager(auth).tokenStore(tokenStore())
                .approvalStoreDisabled();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // @formatter:off
        clients.jdbc(dataSource)
                .passwordEncoder(passwordEncoder)
                .withClient("my-trusted-client")
                .authorizedGrantTypes("password""authorization_code",
                        "refresh_token""implicit")
                .authorities("ROLE_CLIENT""ROLE_TRUSTED_CLIENT")
                .scopes("read""write""trust")
                .resourceIds("oauth2-resource")
                .accessTokenValiditySeconds(60).and()
                .withClient("my-client-with-registered-redirect")
                .authorizedGrantTypes("authorization_code")
                .authorities("ROLE_CLIENT").scopes("read""trust")
                .resourceIds("oauth2-resource")
                .redirectUris("http://anywhere?key=value").and()
                .withClient("my-client-with-secret")
                .authorizedGrantTypes("client_credentials""password")
                .authorities("ROLE_CLIENT").scopes("read")
                .resourceIds("oauth2-resource").secret("secret");
        // @formatter:on
    }



너무 길어져서 여기까지만 해본다...

나는 잘 되었고.. 다른 분들도 잘 되었기를 기원한다.