-
OAuth2.0과 JWT적용 - 1스프링 2023. 1. 17. 19:22
Security의 설정은 다음과 같이 하였다.
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final OAuthUserService oAuthUserService; private final OAuthSuccess oAuthSuccess; @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .cors() .and() .csrf().disable() .authorizeHttpRequests().anyRequest().permitAll() .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //세션사용 안함 .and() .oauth2Login() //OAuthLogin 설정 .successHandler(oAuthSuccess) .userInfoEndpoint() // oauth2Login 설정을 시작 .userService(oAuthUserService); // 로그인을 oAuthUserService에서 처리 return http.build(); } }
WebSecurityConfigurerAdaptor가 이용이 불가능해지고, antMatcher와 AuthorizeRequets도 모두
이용이 불가능해 졌다.
따라서 위와같이 구성하였다.
rest api이기 때문에 http 로그인 페이지 폼이 없고, csrf 보안이 필요없다. 또한 토큰기반 인증을 할꺼니까 세션도 생성을 하지 않는다.
OAuth로그인의 정보를 받아올 Attribute를 생성한다.
카카오, 구글, 네이버 모두 인증방식이 다르기때문에 후에 switch를 이용하여 더 확장시킬 수 있도록 하였다.
@Getter @AllArgsConstructor public class OAuthAttribute { private Map<String, Object> attributes; private String attributeKey; private String email; private String name; /** * 후에 다른 OAuth서비스 확장 * @param provider * @param attributeKey * @param attributes * @return */ public static OAuthAttribute of(String provider, String attributeKey, Map<String, Object> attributes) { switch (provider) { case "google": return googleAttribute(attributeKey, attributes); default: throw new RuntimeException(); } } private static OAuthAttribute googleAttribute(String attributeKey, Map<String, Object> attributes) { return new OAuthAttribute(attributes, attributeKey, (String) attributes.get("email"), (String) attributes.get("name")); } }
OAuth2UserService 인터페이스를 구현한 OAuthUserService를 만들어준다.
oAuth2UserService.loadUser를 통해 유저 정보를 가져온다.
DefaultOAuth2UserService 객체를 성공정보를 바탕으로 만든다.
생성된 Service 객체로 부터 Member를 받는다.
registrationId는 현재의 서비스가 구글인지, 카카오인지 구분해주는 역할을 하고,
userNameAttribute는 OAuth시 PK의 역할을 한다고 생각하면 된다.
public class OAuthUserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> { @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService = new DefaultOAuth2UserService(); OAuth2User oAuth2User = oAuth2UserService.loadUser(userRequest); String registrationId = userRequest.getClientRegistration().getRegistrationId(); String userNameAttributeName = userRequest.getClientRegistration() .getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName(); OAuthAttribute oAuthAttribute = OAuthAttribute.of(registrationId, userNameAttributeName, oAuth2User.getAttributes()); Map<String, Object> memberAttribute = makeMap(oAuthAttribute); return new DefaultOAuth2User( Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")), memberAttribute, "email"); } private static Map<String, Object> makeMap(OAuthAttribute oAuthAttribute) { Map<String, Object> memberAttribute = new HashMap<>(); memberAttribute.put("id", oAuthAttribute.getAttributeKey()); memberAttribute.put("key", oAuthAttribute.getAttributeKey()); memberAttribute.put("email", oAuthAttribute.getEmail()); memberAttribute.put("name", oAuthAttribute.getName()); return memberAttribute; } }
다음은 서비스와 인증이 성공하면 처리할 Handler를 등록한다.
Success Handler에 진입했다는 것은, 로그인이 완료되었다는 뜻이다.
성공하면 JWT토큰을 발행해주도록 한다.
@Component @RequiredArgsConstructor public class OAuthSuccess extends SimpleUrlAuthenticationSuccessHandler { private final TokenService tokenService; private final ObjectMapper objectMapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal(); Map<String, Object> attributes = oAuth2User.getAttributes(); MemberOAuthInfo memberOAuthInfo = new MemberOAuthInfo((String) attributes.get("name"), (String) attributes.get("email")); Token token = tokenService.generateToken(memberOAuthInfo.email(), memberOAuthInfo.name()); response.addHeader("Access", token.getAccessToken()); response.addHeader("Refresh", token.getRefreshToken()); response.setContentType("application/json;charset=UTF-8"); PrintWriter writer = response.getWriter(); writer.print(objectMapper.writeValueAsString(token)); } }
728x90'스프링' 카테고리의 다른 글
JWT 토큰 체크 (0) 2023.01.19 OAuth2.0과 JWT적용 - 2 (0) 2023.01.17 security버전 (0) 2023.01.15 [Test] Mockito 기반의 Spring 단위 테스트 (0) 2023.01.12 [Test] 단위테스트 (0) 2023.01.12