SpringBoot [스프링부트] Sprig Security Oauth2 만들기(3)
1. 프로젝트 개요
Oauth2가 어떻게 적용하는지만 확인을 위한 것이므로 간략하게 만들겠습니다. 밑에 조건만 만들겠습니다.
- User가 로그인 전에 접속할 수 있는 URL
- User가 로그인 후에만 접속할 수 있는 URL
- User가 로그인 했지만 ROLE= GUEST일 때는 접근 못하는 URL
1. User Entity
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(name = "user_email")
private String email;
@Column(name = "user_name")
private String name;
@Column(name = "user_picture_source")
private String picture;
@Enumerated(EnumType.STRING)
@Column(name = "user_role")
private Role role;
@Builder
public user(String email, String name, String picture, Role role){
this.email=email;
this.name=name;
this.picture=picture;
this.role=role;
}
public User Update(String name, String picture){
this.name=name;
this.picture=picture;
return this;
}
public String getRoleKey(){
return role.getKey();
}
}
2. Role Enum
@Getter
@RequiredArgsConstructor
public enum Role {
GUEST("ROLE_GUEST", "손님"),
USER("ROLE_USER", "사용자");
private final String key;
private final String title;
}
3. UserRepository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
4. OauthAttributes
@Getter
public class OauthAttributes {
public Map<String, Object> attributes;
private String nameAttributeKey;
private String name;
private String email;
private String picture;
@Builder
public OauthAttributes(Map<String, Object> attributes, String nameAttributeKey, String name, String email
,String picture){
this.attributes=attributes;
this.nameAttributeKey=nameAttributeKey;
this.name=name;
this.email=email;
this.picture=picture;
}
public static OauthAttributes of(String registrationId, String userNameAttributeName, Map<String,Object> attributes){
return ofGoogle(userNameAttributeName, attributes);
}
private static OauthAttributes ofGoogle(String userNameAttributeName, Map<String,Object> attributes){
return OauthAttributes.builder()
.name((String) attributes.get("name"))
.email((String)attributes.get("email"))
.nameAttributeKey(userNameAttributeName)
.attributes(attributes)
.picture((String) attributes.get("picture"))
.build();
}
public User toEntity(){
return User.builder()
.email(email)
.name(name)
.picture(picture)
.role(Role.GUEST)
.build();
}
}
- of에서는 GoogleOauth, Kakao, Facebook 등등 어떤 API Server를 써주는지 로직을 따로 두지만 저희는 Google만 쓰므로 바로 ofGoogle로 넘겨줍니다.
- ofGoogle에서는 넘어온 attributes을 기반으로 OuathAttributes를 만들어줍니다.
- toEntity는 OauthAttributes에 있는 값들로 User Entity를 생성합니다.
5. SessionUser
@Getter
@NoArgsConstructor
public class SessionUser implements Serializable {
private String name;
private String email;
private String picture;
public SessionUser(String name, String email, String picture) {
this.name = name;
this.email = email;
this.picture = picture;
}
}
- User Entity로 Session을 넣으려 한다면 직렬화 오류가 뜹니다. 그렇다고 User를 직렬화 하는 것은 옳은 방법은 아닙니다. Entity는 DB에 저장되는 객체이며 여러 가지 관계가 포함되는데 이것이 성능 이슈로 이어질 수 있습니다. 그래서 SessionUser를 만들어서 활용합니다.
6. CustomOauth2UserService
@RequiredArgsConstructor
@Service
@Transactional
public class CustomOauth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final UserRepository userRepository;
private final HttpSession httpSession;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);
String registrationId = userRequest.getClientRegistration().getRegistrationId();
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint()
.getUserNameAttributeName();
OauthAttributes attributes = OauthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());
User user = saveOrUpdate(attributes);
httpSession.setAttribute("loginUser", new SessionUser(user.getName(),user.getEmail(),user.getPicture()));
return new DefaultOAuth2User(Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())),
attributes.getAttributes(), attributes.getNameAttributeKey());
}
private User saveOrUpdate(OauthAttributes attributes){
return userRepository.findByEmail(attributes.getEmail())
.map(e -> e.update(e.getName(), e.getPicture()))
.orElse(attributes.toEntity());
}
}
- registrationId: 로그인을 진행 중인 서비스를 구분하는 코드입니다.
- userNameAttributeName: Oauth2 로그인 진행 시 키가 되는 필드 값입니다. primary key라고 생각하면 됩니다. google의 기본 코드는 "sub"입니다.
- HttpSession을 이용해서 Session을 만들어줍니다.
지금까지 Entity, Dto, Repository, Service를 만들었습니다. 다음은 이것들을 활용할 Configuration을 만들어보겠습니다. 감사합니다.
모든 코드는 아래 링크에서 확인 가능합니다.
https://github.com/rlaehdals/Oauth2Example
참고
http://www.yes24.com/Product/Goods/83849117
'SpringBoot > spring security' 카테고리의 다른 글
SpringBoot [스프링부트] Spring Security JWT 만들기(0) (0) | 2022.01.22 |
---|---|
SpringBoot [스프링부트] Spring Security Oauth2 만들기 (5) (0) | 2022.01.22 |
SpringBoot [스프링부트] Spring Security Oauth2 만들기 (4) (0) | 2022.01.21 |
SpringBoot [스프링부트] Spring Security Oauth2 만들기(2) (0) | 2022.01.20 |
SpringBoot [스프링부트] Spring Security Oauth2 만들기(1) (0) | 2022.01.20 |
댓글
이 글 공유하기
다른 글
-
SpringBoot [스프링부트] Spring Security Oauth2 만들기 (5)
SpringBoot [스프링부트] Spring Security Oauth2 만들기 (5)
2022.01.22 -
SpringBoot [스프링부트] Spring Security Oauth2 만들기 (4)
SpringBoot [스프링부트] Spring Security Oauth2 만들기 (4)
2022.01.21 -
SpringBoot [스프링부트] Spring Security Oauth2 만들기(2)
SpringBoot [스프링부트] Spring Security Oauth2 만들기(2)
2022.01.20 -
SpringBoot [스프링부트] Spring Security Oauth2 만들기(1)
SpringBoot [스프링부트] Spring Security Oauth2 만들기(1)
2022.01.20