feat(user-service): Oauth 로그인시 token생성

Oauth 로그인시 response header에 access token, refresh token을 담아 보냄.
This commit is contained in:
hoon7566
2022-02-18 14:01:39 +09:00
parent 47faea59e4
commit 795606334a
10 changed files with 85 additions and 107 deletions

View File

@@ -3,6 +3,5 @@ package com.justpickup.userservice.domain.jwt.service;
import com.justpickup.userservice.domain.user.dto.JwtTokenDto;
public interface RefreshTokenService {
void updateRefreshToken(Long id, String refreshToken);
JwtTokenDto refreshJwtToken(String accessToken, String refreshToken);
}

View File

@@ -8,8 +8,12 @@ import com.justpickup.userservice.domain.user.repository.UserRepository;
import com.justpickup.userservice.domain.jwt.utils.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -21,17 +25,11 @@ import java.util.stream.Collectors;
@Transactional(readOnly = true)
@Slf4j
public class RefreshTokenServiceImpl implements RefreshTokenService {
private final UserDetailsService userDetailsService;
private final UserRepository userRepository;
private final JwtTokenProvider jwtTokenProvider;
@Transactional
@Override
public void updateRefreshToken(Long id, String refreshToken) {
User user = userRepository.findById(id)
.orElseThrow(() -> new NotExistUserException("사용자 고유번호 : " + id + "는 없는 사용자입니다."));
user.changeRefreshToken(refreshToken);
}
@Transactional
@Override
@@ -56,7 +54,7 @@ public class RefreshTokenServiceImpl implements RefreshTokenService {
", refreshToken = " + refreshToken);
}
Authentication authentication = jwtTokenProvider.getAuthentication(user.getEmail());
Authentication authentication = getAuthentication(user.getEmail());
List<String> roles = authentication.getAuthorities()
.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
@@ -70,4 +68,10 @@ public class RefreshTokenServiceImpl implements RefreshTokenService {
.refreshToken(newRefreshToken)
.build();
}
public Authentication getAuthentication(String email) {
UserDetails userDetails = userDetailsService.loadUserByUsername(email);
return new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
}
}

View File

@@ -16,12 +16,9 @@ import java.util.List;
import java.util.UUID;
@Component
@RequiredArgsConstructor
@Slf4j
public class JwtTokenProvider {
private final UserDetailsService userDetailsService;
@Value("${token.access-expired-time}")
private long ACCESS_EXPIRED_TIME;
@@ -60,10 +57,7 @@ public class JwtTokenProvider {
.compact();
}
public Authentication getAuthentication(String email) {
UserDetails userDetails = userDetailsService.loadUserByUsername(email);
return new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
}
public String getUserId(String token) {
try {

View File

@@ -16,9 +16,9 @@ public class Customer extends User {
@Enumerated(EnumType.STRING)
private AuthType oauthType;
public Customer(String email, String password, String name, String phoneNumber, AuthType oauthType) {
super(email, password, name, phoneNumber,Role.USER);
super(email, password, name, phoneNumber,null);
this.dtype = Customer.class.getSimpleName();
this.oauthType = oauthType;
}
}

View File

@@ -1,14 +0,0 @@
package com.justpickup.userservice.domain.user.entity;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum Role {
GUEST("ROLE_GUEST", "손님"),
USER("ROLE_USER", "일반 사용자");
private final String key;
private final String title;
}

View File

@@ -12,7 +12,7 @@ import javax.persistence.*;
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User extends BaseEntity {
public abstract class User extends BaseEntity {
@Id @GeneratedValue
@Column(name = "user_id")
@@ -28,19 +28,8 @@ public class User extends BaseEntity {
private String refreshTokenId;
@Enumerated(EnumType.STRING)
private Role role;
@Column(insertable = false,updatable = false)
private String dtype;
public User(String email, String password, String name, String phoneNumber, Role role) {
this.email = email;
this.password = password;
this.name = name;
this.phoneNumber = phoneNumber;
this.role = role;
}
protected String dtype;
public User(String email, String password, String name, String phoneNumber, String refreshTokenId) {
this.email = email;

View File

@@ -9,6 +9,8 @@ import com.justpickup.userservice.domain.user.dto.StoreOwnerDto;
import com.justpickup.userservice.domain.user.entity.StoreOwner;
public interface UserService extends OAuth2UserService<OAuth2UserRequest, OAuth2User> {
void updateRefreshToken(Long id, String refreshToken);
CustomerDto findCustomerByUserId(Long userId);
StoreOwner saveStoreOwner(StoreOwnerDto storeOwnerDto);
}

View File

@@ -1,60 +1,54 @@
package com.justpickup.userservice.domain.user.service;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.justpickup.userservice.domain.jwt.utils.JwtTokenProvider;
import com.justpickup.userservice.domain.user.dto.CustomerDto;
import com.justpickup.userservice.domain.user.dto.OAuthAttributeDto;
import com.justpickup.userservice.domain.user.dto.StoreOwnerDto;
import com.justpickup.userservice.domain.user.dto.OAuthAttributeDto;
import com.justpickup.userservice.domain.user.dto.OAuthAttributeDto;
import com.justpickup.userservice.domain.user.entity.Customer;
import com.justpickup.userservice.domain.user.entity.StoreOwner;
import com.justpickup.userservice.domain.user.entity.User;
import com.justpickup.userservice.domain.user.exception.NotExistUserException;
import com.justpickup.userservice.domain.user.repository.CustomerRepository;
import lombok.*;
import com.justpickup.userservice.domain.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.core.env.Environment;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Collections;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Collections;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
@Slf4j
public class UserServiceImpl implements UserService, UserDetailsService {
private final CustomerRepository customerRepository;
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final HttpServletResponse response;
private final Environment env;
private final HttpServletRequest request;
private final JwtTokenProvider jwtTokenProvider;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -85,31 +79,11 @@ public class UserServiceImpl implements UserService, UserDetailsService {
return userRepository.save(storeOwner);
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public static class AuthResponse{
private String id;
private String name;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
static class AuthRequest {
private String code;
private String client_id;
private String client_secret;
}
@Override
@Transactional(readOnly = false)
@Transactional
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService<OAuth2UserRequest,OAuth2User> delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);
@@ -124,28 +98,53 @@ public class UserServiceImpl implements UserService, UserDetailsService {
// OAuth2UserService
OAuthAttributeDto attributeDto = OAuthAttributeDto.of(registrationId, userNameAttributeName,oAuth2User.getAttributes());
Customer customer = customerRepository.save(
customerRepository.findByEmail(attributeDto.getEmail())
.orElse(attributeDto.toEntity(attributeDto))
);
Customer customer = saveCustomer(attributeDto);
// TODO: 2022/02/16 Response에 token 담아 보내기
String userEmail = customer.getEmail();
Collection<? extends GrantedAuthority> authorities = loadUserByUsername(userEmail).getAuthorities();
List<String> roles = authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
String accessToken = jwtTokenProvider.createJwtAccessToken(userEmail, request.getRequestURI(), roles);
String refreshToken = jwtTokenProvider.createJwtRefreshToken();
updateRefreshToken(customer.getId(), jwtTokenProvider.getRefreshTokenId(refreshToken));
customer.changeRefreshToken(refreshToken);
response.setHeader("Access-token",accessToken);
response.setHeader("refresh-token",refreshToken);
return new DefaultOAuth2User(
Collections.singleton(new SimpleGrantedAuthority(customer.getRole().getKey()))
authorities
, attributeDto.getAttributes()
, attributeDto.getNameAttributeKey());
}
@Getter
public static class UserPayload implements Serializable {
private String name;
private String email;
public UserPayload(Customer user){
this.name = user.getName();
this.email = user.getEmail();
}
@Transactional
public Customer saveCustomer(OAuthAttributeDto attributeDto){
return customerRepository.save(
customerRepository.findByEmail(attributeDto.getEmail())
.orElse(attributeDto.toEntity(attributeDto))
);
}
@Transactional
@Override
public void updateRefreshToken(Long id, String refreshToken) {
User user = userRepository.findById(id)
.orElseThrow(() -> new NotExistUserException("사용자 고유번호 : " + id + "는 없는 사용자입니다."));
user.changeRefreshToken(refreshToken);
}
}

View File

@@ -3,6 +3,7 @@ package com.justpickup.userservice.global.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.justpickup.userservice.domain.jwt.service.RefreshTokenServiceImpl;
import com.justpickup.userservice.domain.jwt.utils.JwtTokenProvider;
import com.justpickup.userservice.domain.user.service.UserService;
import com.justpickup.userservice.global.dto.LoginRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -31,7 +32,7 @@ public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFil
private final AuthenticationManager authenticationManager;
private final JwtTokenProvider jwtTokenProvider;
private final RefreshTokenServiceImpl refreshTokenServiceImpl;
private final UserService userService;
// login 리퀘스트 패스로 오는 요청을 판단
@Override
@@ -67,7 +68,7 @@ public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFil
String accessToken = jwtTokenProvider.createJwtAccessToken(userId, request.getRequestURI(), roles);
String refreshToken = jwtTokenProvider.createJwtRefreshToken();
refreshTokenServiceImpl.updateRefreshToken(Long.valueOf(userId), jwtTokenProvider.getRefreshTokenId(refreshToken));
userService.updateRefreshToken(Long.valueOf(userId), jwtTokenProvider.getRefreshTokenId(refreshToken));
Map<String, String> tokens = Map.of(
"access_token", accessToken,

View File

@@ -4,6 +4,7 @@ import com.justpickup.userservice.domain.jwt.service.RefreshTokenServiceImpl;
import com.justpickup.userservice.domain.jwt.utils.JwtTokenProvider;
import com.justpickup.userservice.domain.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@@ -19,10 +20,10 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final ApplicationContext applicationContext;
private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final JwtTokenProvider jwtTokenProvider;
private final RefreshTokenServiceImpl refreshTokenServiceImpl;
private final UserService userService;
@@ -34,7 +35,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
LoginAuthenticationFilter loginAuthenticationFilter =
new LoginAuthenticationFilter(authenticationManagerBean(), jwtTokenProvider, refreshTokenServiceImpl);
new LoginAuthenticationFilter(authenticationManagerBean()
,applicationContext.getBean(JwtTokenProvider.class)
,applicationContext.getBean(UserService.class));
loginAuthenticationFilter.setFilterProcessesUrl("/login");
http.csrf().disable();