Spring Boot/Security
Spring Boot - spring security + oauth2
최-코드
2024. 4. 11. 23:23
각각의 필터가 동작하는 주소
OAuth2AuthorizationRequestRedirectFilter : /oauth2/authorization/서비스명
OAuth2LoginAuthenticationFilter : /login/oauth2/code/서비스명 ( redirect_uri이다. )
이 때 서비스명은 카카오면 kakao와 같이 registrationId를 적어주면 된다.
기본적인 로직은 /oauth2/authorization/서비스명으로 요청이 들어오면 서비스명 즉, registrationId에 해당하는 설정 파일을 참고하여 authorization-uri을 통해 로그인 페이지로 이동한다. 이후 로그인이 성공하면 redirect_uri 경로로 리다이렉트하는데, 이 때 code를 붙여서 리다이렉트를 진행한다.
properties 설정만 하면 OAuth2AuthorizationRequestRedirectFilter, OAuth2LoginAuthenticationFilter, OAuth2LoginAuthenticationProvider까지는 자동으로 이뤄진다. 따라서 UserDetailsService와 UserDetails만 구현하면 된다.
properties
spring.security.oauth2.client.registration.kakao.client-name=kakao
spring.security.oauth2.client.registration.kakao.client-id=앱키 입력
spring.security.oauth2.client.registration.kakao.client-secret=보안에 client secret 입력
spring.security.oauth2.client.registration.kakao.redirect-uri=https://localhost:8080/login/oauth2/code/kakao
spring.security.oauth2.client.registration.kakao.authorization-grant-type=authorization_code #임의 설정 X 정해진 방식이 있음
spring.security.oauth2.client.registration.kakao.client-authentication-method=client_secret_post #not POST
spring.security.oauth2.client.provider.kakao.authorization-uri=https://kauth.kakao.com/oauth/authorize
spring.security.oauth2.client.provider.kakao.token-uri=https://kauth.kakao.com/oauth/token
spring.security.oauth2.client.provider.kakao.user-info-uri=https://kapi.kakao.com/v2/user/me
spring.security.oauth2.client.provider.kakao.user-name-attribute=id
SecurityConfig.java
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final CustomOAuth2UserService customOAuth2UserService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable);
http
.formLogin(AbstractHttpConfigurer::disable);
http
.httpBasic(AbstractHttpConfigurer::disable);
http //oauth2Login()은 oauth2 관련 필터 사용하게 하는 역할
.oauth2Login((oauth2)->oauth2
//리소스 서버에서 정보를 가져왔을 때 실행할 UserService 설정
.userInfoEndpoint((userInfoEndpoint)->userInfoEndpoint
.userService(customOAuth2UserService))
//.defaultSuccessUrl("/success"); 로그인 성공시 이동할 url 설정
http
.authorizeHttpRequests((auth)->auth
.requestMatchers("/","/oauth2/**","/login/**").permitAll()
.anyRequest().authenticated());
return http.build();
}
}
CustomOAuth2User.java
// UserDetails와 유사
public class CustomOAuth2User implements OAuth2User {
private final OAuth2Response oAuth2Response;
private final String role;
public CustomOAuth2User(OAuth2Response oAuth2Response, String role) {
this.oAuth2Response = oAuth2Response;
this.role = role;
}
@Override
public Map<String, Object> getAttributes() {
return null;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(role));
return authorities;
}
@Override
public String getName() {
return oAuth2Response.getnickname();
}
}
CustomOAuth2UserService.java
@Service
@RequiredArgsConstructor
// UserDetailsService와 유사
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
private final UserRepository userRepository;
@Override
// OAuth2UserRequest에는 access token과 설정 정보가 포함되어 있다.
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
// user 가져오기
OAuth2User oAuth2User = super.loadUser(userRequest);
// getAttributes()에는 리소스 서버에서 보낸 유저 정보가 있다.
System.out.println(oAuth2User.getAttributes());
// userRequest.getClientRegistration().getRegistrationId()로
// 서비스명 받아온 뒤에 서비스에 맞는 Response 생성
OAuth2Response oAuth2Response = new KakaoResponse(oAuth2User.getAttributes());
String role = "ROLE_USER";
Optional<UserEntity> byRegistrationId = userRepository
.findByRegistrationId(oAuth2Response.getId());
if (byRegistrationId.isPresent()) {
UserEntity user = byRegistrationId.get();
user.setNickname(oAuth2Response.getnickname());
} else {
UserEntity user = new UserEntity();
user.setNickname(oAuth2Response.getnickname());
user.setRegistrationId(oAuth2Response.getId());
user.setRole(role);
userRepository.save(user);
}
//UserDetailsService와 다른 점은 이 때 리턴한 것은 그저 SecurityContextHolder에 저장하기 위함
return new CustomOAuth2User(oAuth2Response, role);
}
}