spring-security-oauth 심층 분석 - 2
2016. 3. 14. 18:27ㆍJava/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 } |
너무 길어져서 여기까지만 해본다...
나는 잘 되었고.. 다른 분들도 잘 되었기를 기원한다.
'Java > Spring Framework' 카테고리의 다른 글
WebFlux framework 번역 (0) | 2018.02.22 |
---|---|
SSE , Server-Sent Event 로 뭔가를 해볼수 있을듯... (1) | 2018.02.22 |
spring-security-oauth 심층 분석 - 1 (0) | 2016.03.14 |
Integration Testing in a Spring Project (0) | 2016.01.19 |
Profile 설정과 Quarts Cron Expression 처리 (0) | 2015.12.15 |
Spring Security 3.2.5 Release 적용 후기 (2) | 2014.09.11 |
스프링을 공부하면서… (0) | 2013.08.30 |
실행환경 아키텍쳐 구성(2.5) (0) | 2013.08.06 |
ANNOTATION (0) | 2013.08.04 |
JSP -> Model2 MVC -> Spring Framework 3단계 게시판 만들기. (8) | 2013.08.04 |