반응형
OAuth2 Authentication이란?
- 외부 Provider(ex. google)을 통해 회원 인증을 처리하는 방식
- 아래 예제에서는 google을 Provider로 처리한다. 따라서 사전에 구글 클라우드 콘솔에 프로젝트 등록이 필요하다.
- OAuth2LoginAuthenticationFilter를 사용한다.
- OAuth2 로그인을 시도한 경우
- Provider에 로그인 인증 요청
- OAuth2LoginAuthenticationProvider를 통해 인증정보(Authentication) 생성
- 해당 과정에서 DefaultOAuth2UserService.loadUser()를 호출
- ThreadLocalSecurityContextHolderStrategy.setContext() 를 호출하여 인증정보를 컨텍스트에 세팅
- HttpSessionSecurityContextRepository.saveContext() 를 호출하여 인증정보를 세션에 저장(세션키: SPRING_SECURITY_CONTEXT)
의존성 추가
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
application.yml
spring:
security:
oauth2:
client:
registration:
google:
client-id: {client_id} // 구글 클라우드 콘솔에서 발급받은 client_id
client-secret: {client_secret} // 구글 클라우드 콘솔에서 발급받은 client_secret
scope: profile, email
User
@Getter
@Builder
public class User {
private String email;
private String password;
private String role;
}
PrincipalUser
@Getter
@RequiredArgsConstructor
public class PrincipalUser implements UserDetails, OAuth2User {
private final User user;
private final Map<String, Object> attributes;
@Override
public String getUsername() {
return user.getEmail();
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority(user.getRole()));
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String getName() {
return (String) attributes.get("name");
}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
}
OAuth2UserService
@Service
public class OAuth2UserService extends DefaultOAuth2UserService {
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);
String provider = userRequest.getClientRegistration().getRegistrationId();
String email = oAuth2User.getAttribute("email");
String oauthEmail = provider + ";" + email;
User user = User.builder()
.email(oauthEmail)
.password(null)
.role("USER")
.build();
// TODO 위 객체를 여기서 데이터베이스에 저장하여 회원가입 처리
return new PrincipalUser(user, oAuth2User.getAttributes());
}
}
SecurityConfig
@EnableWebSecurity(debug = true)
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(
HttpSecurity http,
OAuth2UserService oAuth2UserService
) throws Exception {
return http
.authorizeRequests(authorize -> {
authorize.requestMatchers("/error/**").permitAll();
authorize.anyRequest().authenticated();
})
.oauth2Login(oauth2 -> {
oauth2.defaultSuccessUrl("/"); // 로그인 성공 후 이동할 페이지 URL
oauth2.userInfoEndpoint(userInfo -> {
userInfo.userService(oAuth2UserService);
});
})
.csrf(AbstractHttpConfigurer::disable)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
DemoController
@RestController
public class DemoController {
@GetMapping("/api/v1/demo")
public String demoV1(@AuthenticationPrincipal PrincipalUser user) {
return user.getUser().getEmail();
}
}
인증 및 API 요청 테스트
- /oauth2/authorization/google 로 접속하거나 인증되지 않은 상태로 /api/v1/demo 요청을 하면 google 로그인 페이지로 이동
- 로그인을 성공하면 /api/v1/demo API를 요청하여 응답이 내려오는지 확인
반응형
'Development > Spring Security' 카테고리의 다른 글
[Spring Security] WebSocketSecurity (0) | 2023.10.29 |
---|---|
[Spring Security] Jwt Authentication(Custom Filter로 직접 구현하기) (0) | 2023.10.29 |
[Spring Security] Basic Authentication (0) | 2023.10.29 |
[Spring Security] Form Authentication (0) | 2023.10.29 |
[Spring Security] 기본 (0) | 2023.10.29 |