Search

์นด์นด์˜ค ๋กœ๊ทธ์ธ - ๊ธฐ๋ณธ ํ”„๋กœ์ ํŠธ

์นด์นด์˜ค ๋กœ๊ทธ์ธ ๊ธฐ๋ณธ ํ”„๋กœ์ ํŠธ

์นด์นด์˜ค ๋กœ๊ทธ์ธ - INDEX

ํ”„๋กœ์ ํŠธ ๋ชฉํ‘œ

Spring Security, OAuth2 Client ์˜์กด์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ, ๋‹จ์ˆœํžˆ OAuth ์ธ์ฆ ์„ค์ •์„ ํ†ตํ•ด ์นด์นด์˜ค ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„

Code

Preview

3.
a.
์นด์นด์˜ค ๋กœ๊ทธ์ธ
b.
2๋‹จ๊ณ„ ์ธ์ฆ

์ž‘์—… ํ”„๋กœ์„ธ์Šค

Preview

๋ฉ”์ธ ํ™”๋ฉด

๋กœ๊ทธ์ธ ํ™”๋ฉด

๋กœ๊ทธ์ธ

1.
์นด์นด์˜ค ๋กœ๊ทธ์ธ
2.
2๋‹จ๊ณ„ ์ธ์ฆ

์นด์นด์˜ค ๋กœ๊ทธ์ธ

2๋‹จ๊ณ„ ์ธ์ฆ

๋ฉ”์ธ ํ™”๋ฉด (๋กœ๊ทธ์ธ ์™„๋ฃŒ)

์ž‘์—… ํ”„๋กœ์„ธ์Šค

1.
ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
โ€ข
build.gradle
โ€ข
spring boot version : 2.x.x
โ€ข
spring security version : 5.x.x
โ€ข
์˜์กด์„ฑ ์„ค์ •
โ—ฆ
Spring Web
โ—ฆ
Spring Boot DevTools
โ—ฆ
Spring Security
โ—ฆ
OAuth2 Client
โ—ฆ
Lombok
โ—ฆ
Thymeleaf
2.
ํ”„๋กœ์ ํŠธ ์„ค์ •
โ€ข
profile ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ
โ—ฆ
application-oauth.properties
โ€ข
profile ํŒŒ์ผ ํฌํ•จํ•˜๊ธฐ
โ—ฆ
application.properties
spring.profiles.include=oauth
Plain Text
๋ณต์‚ฌ
3.
์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์„ค์ •
โ€ข
~/config/SecurityConfig.java
4.
์š”์ฒญ ๊ฒฝ๋กœ ๋งคํ•‘
โ€ข
~/controller/HomController.java
โ—ฆ
๋ฉ”์ธ ํ™”๋ฉด
โ–ช
: /
โ–ช
index.html

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

1.
ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
2.
ํ”„๋กœ์ ํŠธ ์„ค์ •
3.
์˜์กด์„ฑ ์„ค์ •
4.
build.gradle

๋ช…๋ น ํŒ”๋ ˆํŠธ [ctrl + shift + P]

Create a gradle Project ์ž…๋ ฅ

ํ”„๋กœ์ ํŠธ ์„ค์ •

1.
Spring Boot Version
2.
Language
3.
Group Id
4.
Artifact Id
5.
packaging type
6.
Java version

Spring Boot Version

Language

Group Id

Artifact Id

packaging type

Java version

์˜์กด์„ฑ ์„ค์ •

1.
Spring Web
2.
Spring boot devtools
3.
Lombok
4.
Thymeleaf
5.
Spring Security
6.
OAuth2 Client

Spring Web

Spring boot devtools

Lombok

Thymeleaf

Spring Security

OAuth2 Client

build.gradle

spring boot 2.x.x
spring security 5.x.x
plugins { id 'java' id 'war' id 'org.springframework.boot' version '2.7.17' id 'io.spring.dependency-management' version '1.0.15.RELEASE' } group = 'com.aloha' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.projectlombok:lombok' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { useJUnitPlatform() }
Java
๋ณต์‚ฌ

ํ”„๋กœ์ ํŠธ ์„ค์ •

โ€ข
profile ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ
โ—ฆ
application-oauth.properties
โ€ข
profile ํŒŒ์ผ ํฌํ•จํ•˜๊ธฐ
โ—ฆ
application.properties
spring.profiles.include=oauth
Plain Text
๋ณต์‚ฌ

profile ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ

Kakao Devleoper ์‚ฌ์ดํŠธ์—์„œ ์•ฑ ์„ค์ • ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
REST API KEY
Client Secret
์œ„ ํŽ˜์ด์ง€์—์„œ ์นด์นด์˜ค ์‚ฌ์ดํŠธ์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ถ”๊ฐ€ ๋ฐ ์„ค์ • ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋‚ด์šฉ์— ๋Œ€ํ•˜์—ฌ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

application-oauth.properties

#Kakao OAuth Settings # client-id : REST API KEY spring.security.oauth2.client.registration.kakao.client-id=[REST API KEY] # client-secret : ๋‚ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ > ๋ณด์•ˆ > Client secret spring.security.oauth2.client.registration.kakao.client-secret=[Client Secret] # redirect-uri : ์‚ฌ์šฉ์ž๊ฐ€ ์นด์นด์˜ค๋กœ ๋กœ๊ทธ์ธ ํ›„ ๋Œ์•„์˜ฌ ์„œ๋ฒ„์˜ URL spring.security.oauth2.client.registration.kakao.redirect-uri=http://localhost:8080/login/oauth2/code/kakao # authorization-grant-type : ์•ก์„ธ์Šค ํ† ํฐ ์š”์ฒญ ์‹œ, ์œ ํ˜•์„ ์ง€์ •ํ•˜๋Š” ํ—ค๋” ์†์„ฑ spring.security.oauth2.client.registration.kakao.authorization-grant-type=authorization_code # scope : ์‚ฌ์šฉ์ž ์ •๋ณด ์š”์ฒญ ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•˜๋Š” ์†์„ฑ # โœ… biz ๊ณ„์ •(์‚ฌ์—…์ž๋“ฑ๋ก๋ฒˆํ˜ธ)์ผ ๊ฒฝ์šฐ์—๋งŒ email ์š”์ฒญ์ด ๊ฐ€๋Šฅ # spring.security.oauth2.client.registration.kakao.scope=profile_nickname, account_email, profile_image spring.security.oauth2.client.registration.kakao.scope=profile_nickname, profile_image # client-name : ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ์ด๋ฆ„ spring.security.oauth2.client.registration.kakao.client-name=Kakao # client-authentication-method : ์ธ์ฆ ์„œ๋ฒ„๋กœ ์š”์ฒญ ์‹œ, ์ง€์ •ํ•  ์š”์ฒญ ๋ฉ”์†Œ๋“œ spring.security.oauth2.client.registration.kakao.client-authentication-method=POST # authorization-uri : ์ธ๊ฐ€ ์ฝ”๋“œ ์š”์ฒญ URI (์ธ์ฆ ์„œ๋ฒ„) spring.security.oauth2.client.provider.kakao.authorization-uri=https://kauth.kakao.com/oauth/authorize # token-uri : ์•ก์„ธ์Šค ํ† ํฐ ์š”์ฒญ URI (์ธ์ฆ ์„œ๋ฒ„) spring.security.oauth2.client.provider.kakao.token-uri=https://kauth.kakao.com/oauth/token # user-info-uri : ์‚ฌ์šฉ์ž ์ •๋ณด ์š”์ฒญ URI (๋ฆฌ์†Œ์Šค ์„œ๋ฒ„) spring.security.oauth2.client.provider.kakao.user-info-uri=https://kapi.kakao.com/v2/user/me # user-name-attribute : ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ณ ์œ  ์‹๋ณ„๊ฐ€ ํ‚ค ์†์„ฑ spring.security.oauth2.client.provider.kakao.user-name-attribute=id
Java
๋ณต์‚ฌ

profile ํŒŒ์ผ ํฌํ•จํ•˜๊ธฐ

application.properties

spring.application.name=kakao # application-oauth.propeties ํŒŒ์ผ ํฌํ•จํ•˜๊ธฐ spring.profiles.include=oauth
Java
๋ณต์‚ฌ
application-[ํ”„๋กœํ•„๋ช…].properties ํ˜•ํƒœ๋กœ ํ”„๋กœํ•„ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋ฉด, application.properties ํŒŒ์ผ์—์„œ spring.profiles.include ์†์„ฑ์œผ๋กœ ํ”„๋กœํ•„๋ช…์„ ์ง€์ •ํ•˜์—ฌ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์„ค์ •

~/config/SecurityConfig.java

@EnableWebSecurity @Configuration public class SecurityConfig { /** * ๐Ÿ” ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์„ค์ • ๋ฉ”์†Œ๋“œ * @param http * @return * @throws Exception */ @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // ๐Ÿ‘ฉโ€๐Ÿ’ผ ์ธ๊ฐ€ ์„ค์ • http.authorizeRequests(requests -> requests .antMatchers("/").permitAll() .anyRequest().authenticated()); // ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ” OAuth2 ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ํ™œ์„ฑํ™” http.oauth2Login(withDefaults()); return http.build(); } }
Java
๋ณต์‚ฌ

์š”์ฒญ ๊ฒฝ๋กœ ๋งคํ•‘

~/controller/HomeController.java

โ€ข
๋ฉ”์ธ ํ™”๋ฉด
โ—ฆ
: /
โ—ฆ
index.html

HomeController.java

@Slf4j @Controller public class HomeController { /** * ๋ฉ”์ธ ํ™”๋ฉด * ๐Ÿ”— [GET] - / * ๐Ÿ“„ index.html * @return */ @GetMapping("/") public String home() { log.info(":::::::::: ๋ฉ”์ธ ํ™”๋ฉด ::::::::::"); return "/index"; } }
Java
๋ณต์‚ฌ

index.html

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>OAuth</title> <!-- bootstrap css --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container col-10 col-lg-4"> <div class="px-4 py-5 mt-5 text-center"> <h1 class="display-5 fw-bold text-body-emphasis">๋ฉ”์ธ ํ™”๋ฉด</h1> </div> <!-- ๋น„ ๋กœ๊ทธ์ธ ์‹œ --> <th:block sec:authorize="isAnonymous()"> <div class="d-grid gap-2"> <a href="/login" class="btn btn-lg btn-primary">๋กœ๊ทธ์ธ</a> </div> </th:block> <!-- ๋กœ๊ทธ์ธ ์‹œ --> <th:block sec:authorize="isAuthenticated()"> <div class="card"> <div class="inner p-4"> <div class="d-flex flex-column align-items-center"> <div class="item my-2 w-100"> <span sec:authentication="principal">์•„์ด๋””</span> </div> </div> </div> </div> <form action="/logout" method="post"> <!-- CSRF TOKEN --> <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"> <div class="d-grid gap-2"> <button type="submit" class="btn btn-lg btn-primary">๋กœ๊ทธ์•„์›ƒ</button> </div> </form> </th:block> </div> <!-- bootstrap js --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script> </body> </html>
HTML
๋ณต์‚ฌ