6 Commits

Author SHA1 Message Date
banjjoknim
5e55eeb462 style(user) : 들여쓰기 변경 2022-03-08 12:58:16 +09:00
banjjoknim
5891775b15 feat : Naver 로그인 타입 추가 2022-03-08 12:53:05 +09:00
banjjoknim
a62fbb7f71 chore : merge main(from spring-security-10) 2022-03-08 02:38:49 +09:00
banjjoknim
35a89db2d5 feat : naver OAuth2 설정 추가 2022-03-08 02:37:10 +09:00
Colt
3f64ef2977 Merge pull request #2 from banjjoknim/spring-security-10
Spring Security 예제 코드 설정 파일 일부 변경
2022-03-06 03:23:44 +09:00
Colt
b07abb8703 Merge pull request #1 from banjjoknim/spring-security-10
스프링부트 시큐리티 10강 - 페이스북 로그인 완료
2022-03-06 03:13:01 +09:00
6 changed files with 87 additions and 16 deletions

View File

@@ -30,6 +30,20 @@ import org.springframework.stereotype.Service
* 구글과 페이스북 측에서 우리에게 보내는 Request에 액세스 토큰과 사용자 정보등의 OAUth2 정보가 모두 포함되어 있다.
*
* 하지만 네이버, 카카오는 스프링 부트에서 기본적인 정보를 제공하지 않기 때문에 따로 해당 정보를 제공하는 클래스를 작성해야 한다.
*
* 우리는 OAuth2-Client 라는 라이브러리를 사용하고 있다.
*
* OAuth2-Client 라이브러리는 구글, 페이스북, 깃허브 등의 Provider를 기본적으로 제공해주지만, 네이버 카카오는 제공해주지 않는다.
*
* 이는 각 나라별로 OAuth2 를 지원해주는 서드 파티가 제공하는 attribute 가 모두 다르기 때문이다. 그래서 현실적으로 모든 곳을 지원해줄 수가 없다.
*
* OAuth2-Client 는 OAuth2ClientProperties 라는 클래스를 통한 자동 설정을 지원해주고 있다.
*
* OAuth2는 여러가지 방식이 있다. Authorization Code Grant Type 방식 등등..
*
* @see org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties
* @see org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter
* @see org.springframework.security.config.oauth2.client.CommonOAuth2Provider
*/
@EnableWebSecurity // 스프링 시큐리티 필터가 스프링 필터체인에 등록되도록 해준다.
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) // 스프링 시큐리티 관련 특정 어노테이션에 대한 활성화 설정을 할 수 있다.
@@ -172,8 +186,8 @@ class PrincipalDetails(
* 이때 UserDetailsService 타입으로 등록되어 있는 빈을 찾아서 해당 빈에 정의된 loadUserByUsername() 을 실행한다.
* ```
*
* @see DaoAuthenticationProvider
* @see AbstractUserDetailsAuthenticationProvider
* @see org.springframework.security.authentication.dao.DaoAuthenticationProvider
* @see org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider
*/
@Service
class PrincipalDetailService(private val userRepository: UserRepository) : UserDetailsService {
@@ -200,9 +214,9 @@ class PrincipalDetailService(private val userRepository: UserRepository) : UserD
* OAuth2UserRequest 정보를 이용해서 loadUser 함수 호출 -> 구글로부터 회원프로필을 받아준다.
* ```
*
* @see OAuth2UserService
* @see DefaultOAuth2UserService
* @see OAuth2UserRequest
* @see org.springframework.security.oauth2.client.userinfo.OAuth2UserService
* @see org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService
* @see org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest
*/
@Service
class PrincipalOAuth2UserService(

View File

@@ -5,7 +5,8 @@ enum class OAuth2Type(
private val createUserInfo: (attributes: Map<String, Any?>) -> OAuth2UserInfo
) {
GOOGLE("google", { attributes -> GoogleUserInfo(attributes) }),
FACEBOOK("facebook", { attributes -> FacebookUserInfo(attributes) });
FACEBOOK("facebook", { attributes -> FacebookUserInfo(attributes) }),
NAVER("naver", { attributes -> NaverUserInfo(attributes) });
fun createOAuth2UserInfo(attributes: Map<String, Any?>): OAuth2UserInfo {
return createUserInfo(attributes)

View File

@@ -53,5 +53,33 @@ class FacebookUserInfo(
override fun getName(): String {
return attributes["name"] as String
}
}
class NaverUserInfo(
/**
* DefaultOAuth2Service#loadUser(OAuth2UserRequest)
* ```kotlin
* val oAuth2User = super.loadUser(userRequest)
* val attributes = oAuth2User.attributes
* ```
*/
private val attributes: Map<String, Any?>
): OAuth2UserInfo {
private val response = attributes["response"] as Map<*, *>
override fun getProviderId(): String {
return response["id"] as String
}
override fun getProvider(): String {
return "naver"
}
override fun getEmail(): String {
return response["email"] as String
}
override fun getName(): String {
return response["name"] as String
}
}

View File

@@ -64,16 +64,13 @@ class UserController {
* @see PrincipalDetailsService
*
*/
@GetMapping("/login") // OAuth2 로그인 및 일반 로그인 모두 principalDetails 로 세션 정보를 얻어올 수 있다.
@GetMapping("/login") // OAuth2 로그인 및 일반 로그인 모두 principalDetails 로 세션 정보를 얻어올 수 있다(다운 캐스팅을 하지 않아도 된다!).
fun login(@AuthenticationPrincipal principalDetails: PrincipalDetails) { // DI(의존성 주입)
println("principalDetailsUser : ${principalDetails.user}")
}
@GetMapping("/test/login")
fun testLogin(
authentication: Authentication,
@AuthenticationPrincipal userDetails: UserDetails
) { // DI(의존성 주입)
fun testLogin(authentication: Authentication, @AuthenticationPrincipal userDetails: UserDetails) { // DI(의존성 주입)
val principalDetailsFromAuthentication = authentication.principal as PrincipalDetails // 다운 캐스팅
println("principalDetailsFromAuthentication : ${principalDetailsFromAuthentication.user}")
println("principalDetailsFromAuthentication : ${principalDetailsFromAuthentication.username}")
@@ -83,10 +80,7 @@ class UserController {
}
@GetMapping("/test/oauth2/login")
fun testOAuth2Login(
authentication: Authentication,
@AuthenticationPrincipal oauth: OAuth2User
) { // DI(의존성 주입)
fun testOAuth2Login(authentication: Authentication, @AuthenticationPrincipal oauth: OAuth2User) { // DI(의존성 주입)
val oAuth2User = authentication.principal as OAuth2User // 다운 캐스팅
println("authentication : ${oAuth2User.attributes}") // OAuth2Service 의 super.loadUser(userRequest).attributes 와 같다.
println("oAuth2User : ${oauth.attributes}")

View File

@@ -16,3 +16,20 @@ spring:
scope:
- email
- public_profile
naver:
client-id: my-naver-client-id
client-secret: my-naver-client-secret
scope:
- name
- email
client-name: Naver
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8080/login/oauth2/code # 구글이나 페이스북은 기본적으로 설정되어 있기 때문에 작성하지 않아도 된다. 반면, 구글이나 페이스북은 주소가 고정되어 있으니 함부로 변경하면 안된다.
provider: # provider를 직접 등록해준다.
naver: # /oauth2/authorization/naver 라는 uri를 타고 이동하면 아래의 authorization-uri 로 이동된다.
authorization-uri: https://nid.naver.com/oauth2.0/authorize
token-uri: https://nid.naver.com/oauth2.0/token
user-info-uri: https://openapi.naver.com/v1/nid/me
user-name-attribute: response # 회원정보를 json으로 받는데 response라는 키값으로 네이버가 리턴해준다.

View File

@@ -0,0 +1,17 @@
<head lang="ko">
<meta charset="utf-8">
<title>로그인 페이지</title>
</head>
<body>
<h1>로그인 페이지</h1>
<hr/>
<form action="/login" method="post">
<input type="text" name="username" placeholder="Username"/><br/>
<input type="password" name="password" placeholder="Password"/><br/>
<button>로그인</button>
</form>
<a href="/oauth2/authorization/google">구글 로그인</a>
<a href="/oauth2/authorization/facebook">페이스북 로그인</a>
<a href="/oauth2/authorization/naver">네이버 로그인</a>
<a href="/joinForm">회원가입을 아직 하지 않으셨나요?</a>
</body>