스프링 시큐리티 구조
OAuth 코드
SecurityConfig.java
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
@RequiredArgsConstructor
@EnableWebSecurity // 스프링 시큐리티 설정 활성화
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// URL별 권한 관리를 설정하는 옵션의 시작 antMatchers를 쓰기위해
.antMatchers("/", "/css/**", "/images/**", "/js/**").permitAll()
// 위의 URL들은 권한 없이도 접근 가능
.antMatchers("/api/**").hasRole(Role.USER.name())
// api로 시작하는 URL은 USER권한이 있는 사람만 접근 가능
.anyRequest().authenticated() // 설정한 값 이외의 URL은 로그인 된 사용자만 접근 가능
.and()
.logout()
.logoutSuccessUrl("/") // 로그아웃 성공시 해당 URL로 이동
.and()
.oauth2Login() // 로그인 기능에 대한 설정
.userInfoEndpoint() // 로그인 이후 사용자 정보를 가져올 때 설정
.userService(customOAuth2UserService);
// customOAuth2UserService를 통해 사용자 정보를 가져온다
// customOAuth2UserService는 UserService의 구현체이다
}
}
CustomOAuth2UserService.java
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@RequiredArgsConstructor
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
//<OAuth2UserRequest, OAuth2User> 제네릭 문법으로 인자로 들어올 정확한 타입을 모르기 때문에 쓰임
private final UserRepository userRepository;
private final HttpSession httpSession;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);
// UserInfo 끝점에서 사용자의 attributes를 가져온 후 OAuth2User를 통해 반환
String registrationId = userRequest.getClientRegistration().getRegistrationId();
// 현재 로그인 진행중인 서비스를 구분하는 코드 구글, 페이스북, 네이버 등
String userNameAttributeName = userRequest.getClientRegistration()
.getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
// OAuth를 지원하는 서비스에서 사용자를 구분하기 위한 유니크 필드가 서로 다르기 때문에
// 각 계정마다 유니크한 id값을 전달받기 위한 코드
// 예를 들어 구글은 sub라는 필드가 유니크 키이고 네이버는 id라는 필드가 유니크 키이다
OAuthAttributes attributes = OAuthAttributes
.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());
// OAuth2UserService를 통해 가져온 oAuth2User의 attribute를 담는 클래스
User user = saveOrUpdate(attributes);
// user에 값이 있다면 update, 값이 없다면 save를 한다
httpSession.setAttribute("user", new SessionUser(user));
// 세션에 사용자 정보를 저장하기 위한 DTO
return new DefaultOAuth2User(
Collections.singleton(
new SimpleGrantedAuthority(user.getRoleKey())),
attributes.getAttributes(),
attributes.getNameAttributeKey()
);
// DefaultOAuth2User에 유저 정보를 담아서 리턴
}
private User saveOrUpdate(OAuthAttributes attributes) {
User user = userRepository.findByEmail(attributes.getEmail())
.map(entity ->entity.update(attributes.getEmail()))
.orElse(attributes.toEntity());
return userRepository.save(user);
}
}