일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- STS
- 프로그래머스
- map
- Spring
- GIT
- spring security
- 코딩테스트
- SpringBoot
- map()
- leetcode
- 스프링
- 유레카
- spring boot
- docker
- EUREKA
- JavaScript
- 스프링 클라우드
- jQuery
- 비동기
- Java
- 스프링부트
- date
- JS
- 자바스크립트
- 도커
- 자바
- gitlab
- Spring Cloud
- IntelliJ
- OAuth
- Today
- Total
RATSENO
[SpringBoot]Spring Boot Security + OAuth 2.0 [Authorization code grant] (2) 본문
[SpringBoot]Spring Boot Security + OAuth 2.0 [Authorization code grant] (2)
RATSENO 2020. 9. 14. 17:10이전 포스팅
에 이어서 진행해 보겠습니다.
두가지 프로젝트 소스로 구성 됩니다.
-
spring boot client application - client_id(ratseno)와 secret_key(secret)를 이미 발급받은것을 전제로 합니다.
-
resouce server - OAuth를 사용하여 authoriztion server를 구성합니다. client application을 식별하기 위한 client_id, secret_key를 이미 가지고 있습니다.
flow는 아래와 같습니다.
- Resource Owner(사용자)는 Client Application에게 Resource Server로 부터 데이터를 가져오도록 요청합니다.
- Resource Server는 Resource Owner(사용자)에게 사용자 자신을 인증하고 데이터를 공유할수 있는 권한을 요청합니다.
- 성공적인 인증 후 Resource Server는 Client Application과 Authrizaition code를 공유합니다.
Resource Server Application
먼저 Resoucer Server입니다. JSON 데이터를 인증 및 반환하는 프로젝트이며, Authorization Server 또한 구성할 것입니다.
maven 프로젝트로 구성됩니다. 프로젝트를 생성 시 spring initializr를 이용하여 import하거나 직접 생성하셔도 됩니다.
저는 한땀 한땀 생성하도록 하겠습니다. IDE는 인텔리제이 커뮤니티를 사용하였습니다.
프로젝트 명은 boot-resouce-server이며 깡통 maven 프로젝트로 생성하였기때문에
이렇게 기본 pom.xml과 프로젝트가 구성됩니다. 이제 필요한 dependency등 pom.xml을 작성합니다.
<?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>org.example</groupId>
<artifactId>boot-resource-server</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
필요한 의존성들을 추가하였습니다.(oauth2, security)
이어서 패키지 및 main 클래스를 작성합니다. spring initializr를 이용하여 생성하신 분들은 스킵하셔도 됩니다.
package com.ratseno; //패키지 구성(가장 상위)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
JSON response로서 return될 model 클래스를 생성합니다.
package com.ratseno.model;
public class Employee {
private String empId;
private String empName;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@Override
public String toString() {
return "Employee{" +
"empId='" + empId + '\'' +
", empName='" + empName + '\'' +
'}';
}
}
JSON response를 반환할 end point GET REST Contorller를 생성합니다.
package com.ratseno.controllers;
import com.ratseno.model.Employee;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
public class EmployeeController {
@GetMapping(value = "/user/getEmployeeList")
public List<Employee> getEmployeeList(){
List<Employee> employees = new ArrayList<>();
Employee employee = new Employee();
employee.setEmpId("emp1");
employee.setEmpName("emp1");
employees.add(employee);
return employees;
}
}
마지막은 spring security 관련 설정 파일을 생성합니다. 이 설정파일에서는 어떤URL을 체크하고, 어떤 사용자가 어떤역할로 접근할지를 정의합니다.
package com.ratseno.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
//resources 하위 정적자원들에 대해 보안구성에서 제외한다.
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//HttpSecurity - 특정 http 요청에 대해 웹 기반 보안을 구성할 수 있다.
//기본적으로 모든 요청에 적용되니만 requestMatcher또는 유사한 방법을 사용하여 제한 할 수 있다.
//authorizeRequests - RequestMatcher 구현(url 패턴)을 사용하여 HttpServletReqeust를 기반으로 접근을 제한 할 수 있다.
//antMatchers - 제공된 ant pattern과 일치할때만 호출되도록 HttpSecurity를 호출할 수 있다.
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/user/getEmployeeList").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin().permitAll()
.and().logout().permitAll();
http.csrf().disable();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationMgr) throws Exception {
authenticationMgr.inMemoryAuthentication().withUser("admin").password("admin")
.authorities("ROLE_ADMIN");
}
}
다음으로 @EnableAuthorizationServer 어노테이션을 이용하여 Authorization Server를 구성합니다.
AuthorizationServcerConfigurer 인터페이스의 메소드를 구현하는 AuthorizationServerConfigurerAdaptar 클래스를
상속받아 정의합니다.
Authorization Server는 authorization end point(예를 들어 /oauth/authorize)에 대한 보안을 진행하지 않습니다.
configure 메서드에 spring security authentication manager를 삽입합니다.in memory client service를 사용하여 서버에 접근할 수 있는 client를 설정합니다.
- client_id : ratseno
- secret_key : secret
package com.ratseno.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("ratseno") //client_id
.secret("secret") //secret_key
.authorizedGrantTypes("authorization_code")
.scopes("read").authorities("CLIENT");
}
}
Client Application
Client Application은 JSON data를 얻기위해 앞에서 만든 Resource Server에 요청을 할것 입니다.
앞에서 설명했듯이 Client Application은 이미 Resource Server에 등록되어 있으며,
client_id : ratseno, secret_key : secret으로 가정하였습니다.
OAuth spec에 의해 기본 uri인 /authorize로 인증을 요청해야합니다. 이 예제에서는 기본 uri로 진행하겠습니다.(변경 가능)
기본 인증 uri와 함께 parameter도 전송해야합니다.
-
response_type - (필수값) 값은 "code" 로 설정해야 합니다.
-
client_id - (필수값) 등록하여 얻은 클라이언트 식별자 입니다. 여기서는 "ratseno" 입니다.
-
redirect_uri - (선택) 성공적으로 권한이 부여된 후, Resource Owner가 redirect_uri로 리디렉션 됩니다.
-
scope - (선택) access request의 범위입니다. Read 또는 Write가 될수 있으며. 여기서는 Read를 사용합니다.
위의 parameter들은 "application/x-www-form-urlencoded" 으로 요청해야 합니다.
프로젝트 명은 boot-client-application, maven 프로젝트로 위의 Resource server와 동일하게 생성합니다.
pom.xml을 작성합니다. 크게 spring과 관련된 의존성은 거의 없습니다.
간단한 화면 구성을 위한 의존성들입니다.(JSP)
<?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>org.example</groupId>
<artifactId>boot-client-application</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
기본 패키지와 메인 클래스를 생성합니다.
package com.ratseno;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
"/getEmployees" uri를 가지며 JSP페이지를 리턴하는 컨트롤러를 생성합니다.
package com.ratseno.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class EmployeeController {
@GetMapping(value = "/getEmployees")
public ModelAndView getEmployeeInfo(){
return new ModelAndView("getEmployees");
}
}
spring boot에서 view를 JSP로 사용하기 위해서는 resources폴더 하위의 application.properties
파일을 이용하여 설정이 필요합니다.
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
server.port=8090
저와 같이 기본 maven 프로젝트로 생성하였다면 해당 파일을 생성하여 작성하시면 됩니다.
jsp파일을 생성하기 위해 webapp - WEB-INF - jsp 폴더를 순서대로 생성하고 getEmployees.jsp 파일을 생성합니다.
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Get Employees</title>
</head>
<body>
<h3 style="color: red;">Get Employee Info</h3>
<div id="getEmployees">
<form:form action="http://localhost:8080/oauth/authorize"
method="post" modelAttribute="emp">
<p>
<label>Enter Employee Id</label>
<div>
response_type : <input type="text" name="response_type" value="code" />
</div>
<div>
client_id : <input type="text" name="client_id" value="ratseno" /><br/>
</div>
<div>
redirect_uri : <input type="text" name="redirect_uri" value="http://localhost:8090/showEmployees" />
</div>
<div>
scope : <input type="text" name="scope" value="read" /><br/>
</div>
<div>
<input type="SUBMIT" value="Get Employee info" />
</div>
</form:form>
</div>
</body>
</html>
이제 boot-client-application과 boot-resource-server를 전부 동작시키고.
http://localhost:8090/getEmployees 경로로 브라우저를 이용하여 접근합니다.
Get Employee info버튼을 클릭하면, Resource Server(포트 8080)의 기본 spring security login form 화면이 뜨게됩니다.
admin, admin을 입력하여 로그인합니다.
다음으로는 jsp페이지에서 요청한 기본 인증 화면(/oauth/authorize)을 볼 수 있습니다.
Approve를 선택 후 Authorize 버튼을 클릭하여 Client Application이 Resource를 접근할 수 있도록 권한을 부여해 줍니다.
지금은 Client Application에 showEmployees를 받아줄 수 있는 uri가 존재하지 않기때문에 에러페이지가 뜨지만,
자세히 살펴보면,
Resource Server에 요청할때 같이 보낸 redirect_uri로 Authorization code가 성공적으로 전달된 것을 확인할 수 있습니다.
다음 포스팅에서는 공유된 Authorization code 을 이용하여 Access Token을 얻고
Access Token을 이용하여 JSON데이터를 가져오는 방법을 살펴보겠습니다.
출처: www.javainuse.com/spring/spring-boot-oauth-introduction
'DEV > SPRING' 카테고리의 다른 글
[1]Spring boot + Spring Security + JWT + MySQL(docker) (0) | 2021.05.09 |
---|---|
[SpringBoot]Spring Boot Security + OAuth 2.0 [Authorization code grant] (3) (0) | 2020.09.15 |
[SpringBoot]Spring Boot Security + OAuth 2.0 [Authorization code grant] (1) (0) | 2020.09.14 |
[SpringBoot]SpringBoot 2.2.x 버전 Junit5에서 Junit4로 변경 (3) | 2020.02.26 |
[SpringBoot]자동 설정 이해 (0) | 2020.02.24 |