Skip to content

OAuth Spring Boot

Byeongjae Jung edited this page Mar 6, 2020 · 1 revision

참고 : https://spring.io/guides/tutorials/spring-boot-oauth2/

OAuth 사이트

Api 사용 요청 후 Client id 와 Client Secret 키를 얻어야함

URL

요청 주소

/oauth2/authorization/{registrationId}

  • registrationId

    • github

    • Google..

OAuth2User

OAuth2User

로그인 된 OAuth User 정보를 검색할 때는 OAuth2User 객체를 활용한다.

  • getAttribute 메서드로 속성 검색
@GetMapping("/user")
    public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
        return Collections.singletonMap("name", principal.getAttribute("name"));
    }

WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapter

HttpSecurity

  • 인증관련 설정할 때 이용
  • 인증일 필요한 경우 혹은 인증 없이 접속할 수 있는 주소 구분하도록 함.
  • 에러 또한 관리할 수 있음
@Override
    protected void configure(HttpSecurity http) throws Exception {
    	// @formatter:off
        http
            .authorizeRequests(a -> a
                .antMatchers("/", "/error", "/webjars/**").permitAll()
                .anyRequest().authenticated()
            )
            .exceptionHandling(e -> e
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) //401
            )
            .oauth2Login();
        // @formatter:on
    }

Logout

WebSecurityConfigurerAdapter

HttpSecurity

/logout (POST) url을 요청하면 spring security에서 자동으로 로그아웃 해줌. -> 이 때 클라이언트 측도 로그아웃된 화면 페이지를 구성해주어야함

http.logout(l -> l
            .logoutSuccessUrl("/").permitAll()
        )

이 또한 로그아웃 성공페이지 주소를 지정할 수 있으며 WebSecurityConfigurerAdapter의 config에서 관리함.

Cookie

WebSecurityConfigurerAdapter

HttpSecurity

http.csrf(c -> c       .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
)

Many JavaScript frameworks have built in support for CSRF (e.g. in Angular they call it XSRF), but it is often implemented in a slightly different way than the out-of-the box behaviour of Spring Security. For instance, in Angular, the front end would like the server to send it a cookie called "XSRF-TOKEN" and if it sees that, it will send the value back as a header named "X-XSRF-TOKEN". We can implement the same behaviour with our simple jQuery client, and then the server-side changes will work with other front end implementations with no or very few changes. To teach Spring Security about this we need to add a filter that creates the cookie.

Js의 프레임 워크는 CSRF를 지원하지만 Spring Security와 기본 동작이 다름 앵귤러 같은 경우 XSRF-TOKEN이라 불리는 쿠키를 보냄 -> 이것을 스프링 시큐리티에 적용하려면 쿠키를 생성하는 필터를 추가해야함

Error

WebSecurityConfigurerAdapter

HttpSecurity

protected void configure(HttpSecurity http) throws Exception {
	// @formatter:off
	http
	    // ... existing configuration
	    .oauth2Login(o -> o
            .failureHandler((request, response, exception) -> {
			    request.getSession().setAttribute("error.message", exception.getMessage());
			    handler.onAuthenticationFailure(request, response, exception);
            })
        );
}

User 판단하여 인증하기 (OAuth2UserService)

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/userinfo/OAuth2UserService.html

@Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService(WebClient rest) {
    DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();
    return request -> {
        OAuth2User user = delegate.loadUser(request);
        if (!"github".equals(request.getClientRegistration().getRegistrationId())) {
        	return user;
        }

        OAuth2AuthorizedClient client = new OAuth2AuthorizedClient
                (request.getClientRegistration(), user.getName(), request.getAccessToken());
        String url = user.getAttribute("organizations_url");
        List<Map<String, Object>> orgs = rest
                .get().uri(url)
                .attributes(oauth2AuthorizedClient(client))
                .retrieve()
                .bodyToMono(List.class)
                .block();

        if (orgs.stream().anyMatch(org -> "spring-projects".equals(org.get("login")))) {
            return user;
        }

        throw new OAuth2AuthenticationException(new OAuth2Error("invalid_token", "Not in Spring Team", ""));
    };
}
@Bean
public WebClient rest(ClientRegistrationRepository clients, OAuth2AuthorizedClientRepository authz) {
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
            new ServletOAuth2AuthorizedClientExchangeFilterFunction(clients, authz);
    return WebClient.builder()
            .filter(oauth2).build();
}

Clone this wiki locally