728x90
OAuth2AuthorizedClient

- OAuth2AuthorizedClient 는 인가받은 클라이언트를 의미하는 클래스다.
- 최종 사용자(리소스 소유자)가 클라이언트에게 리소스에 접근할 수 있는 권한을 부여하면, 클라이언트를 인가된 클라이언트로 간주한다
- OAuth2AuthorizedClient 는 AccessToken과 RefreshToken을 ClientRegistration (클라이언트)와 권한을 부여한 최종 사용자인 Principal과 함께 묶어 준다
- OAuth2AuthorizedClient 의 AccessToken 을 사용해서 리소스 서버의 자원에 접근 할 수 있으며 인가서버와의 통신으로 토큰을 검증할 수 있다
- OAuth2AuthorizedClient 의 ClientRegistration과 AccessToken을 사용해서 UserInfo 엔드 포인트로 요청할 수 있다
OAuth2AuthorizedClientRepository

- OAuth2AuthorizedClientRepository 는 다른 웹 요청이 와도 동일한 OAuth2AuthorizedClient 를 유지하는 역할을 담당한다.
- OAuth2AuthorizedClientService 에게 OAuth2AuthorizedClient 의 저장, 조회, 삭제 처리를 위임한다
OAuth2AuthorizedClientService

- OAuth2AuthorizedClientService 는 애플리케이션 레벨에서 OAuth2AuthorizedClient 를 관리(저장, 조회, 삭제 )하는 일이다.
웹 어플리케이션에서 활용

- OAuth2AuthorizedClientRepository 나 OAuth2AuthorizedClientService 는 OAuth2AuthorizedClient 에서 OAuth2AccessToken 을 찾을 수 있는 기능을 제공하므로 보호 중인 리소스 요청을 시작할 때 사용할 수 있다
OAuth2AuthorizationCodeGrantFilter

- Authorization Code Grant 방식으로 권한 부여 요청을 지원하는 필터
- 인가서버로부터 리다이렉트 되면서 전달된 code를 인가서버의 Access Token으로으로 교환한다.
- OAuth2AuthorizedClientRepository를 사용하여 OAuth2AuthorizedClient 를 저장 후 클라이언트의 Redirect Uri로 이동한다
- 해당 필터는 실제 최종 로그인까지의 처리까지 진행하는 것이 아닌 인가 서버까지만 인증을 진행한다.
- 실행 조건
- 요청 파라미터에 code와state 값이 존재하는지 확인
- OAuth2AuthorizationRequest 객체가 존재하는지 확인
- 위 두 조건이 참이 되는 경우는 Client에서 인증 서버에 1단계 요청(Code)을 정상적으로 완료를 했을 때이다.
Test
HomeController
@Controller
public class HomeController {
@GetMapping("/home")
public String home() {
return "home";
}
}
home.html
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
function authorizationCode(){
window.location = new URL('http://localhost:8081/oauth2/authorization/keycloak');
}
function password(){
window.location = new URL('http://localhost:8081/oauth2/authorization/keycloak2');
}
function clientCredentials(){
window.location = new URL('http://localhost:8081/oauth2/authorization/keycloak3');
}
</script>
</head>
<body>
<div>Welcome</div>
<form sec:authorize="isAnonymous()" action="#">
<p><input type="button" onclick="authorizationCode()" value="AuthorizationCode Grant" />
<p><input type="button" onclick="password()" value="Resource Owner Password Grant" />
<p><input type="button" onclick="clientCredentials()" value="Client Credentials Grant" />
</form>
</body>
</html>
OAuth2ClientConfig
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
authRequest -> authRequest.antMatchers("/home", "/client").permitAll().anyRequest().authenticated())
.oauth2Client(Customizer.withDefaults());
http.logout().logoutSuccessUrl("/home");
return http.build();
}
ClientController
@Controller
public class ClientController {
@Autowired
private OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository;
@Autowired
private OAuth2AuthorizedClientService oAuth2AuthorizedClientService;
@GetMapping("/client")
public String client(HttpServletRequest request, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String clientRegistrationId = "keycloak";
OAuth2AuthorizedClient oAuth2AuthorizedClient1 = oAuth2AuthorizedClientRepository.loadAuthorizedClient(
clientRegistrationId, authentication, request);
OAuth2AuthorizedClient oAuth2AuthorizedClient2 = oAuth2AuthorizedClientService.loadAuthorizedClient(
clientRegistrationId, authentication.getName());
OAuth2AccessToken accessToken = oAuth2AuthorizedClient1.getAccessToken();
OAuth2UserService oAuth2UserService = new DefaultOAuth2UserService();
OAuth2User oAuth2User = oAuth2UserService.loadUser(
new OAuth2UserRequest(oAuth2AuthorizedClient1.getClientRegistration(), accessToken));
OAuth2AuthenticationToken authenticationToken = new OAuth2AuthenticationToken(oAuth2User,
Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")),
oAuth2AuthorizedClient1.getClientRegistration().getRegistrationId());
SecurityContextHolder.getContext().setAuthentication(authenticationToken); //시큐리티 컨텍스트에 인증 객체 담기
model.addAttribute("accessToken", accessToken.getTokenValue());
model.addAttribute("refreshToken", oAuth2AuthorizedClient1.getRefreshToken().getTokenValue());
model.addAttribute("principalName", oAuth2User.getName());
model.addAttribute("clientName", oAuth2AuthorizedClient1.getClientRegistration().getClientName());
return "client";
}
}
Client.html
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div>Welcome</div><p></p>
<div sec:authorize="isAuthenticated()"><a th:href="@{/logout}">Logout</a></div><br>
<div sec:authorize="isAuthenticated()">principalName: <span th:text="${principalName}">인가받은 클라이언트</span></div><br>
<div sec:authorize="isAuthenticated()">clientName: <span th:text="${clientName}">인가받은 클라이언트</span></div><br>
<div sec:authorize="isAuthenticated()">accessToken: <span th:text="${accessToken}">인가받은 클라이언트</span></div><br>
<div sec:authorize="isAuthenticated()">refreshToken: <span th:text="${refreshToken}">인가받은 클라이언트</span></div><br>
</body>
</html>
Footer
- OAuth2AuthorizedClientRepository, OAuth2AuthorizedClientService 를 통해서 client 인증을 할 수 있으며 해당 애플리케이션 같은 경우는 실제 로그인 처리가 된 것이 아닌 익명사용자로 인증이 된 것이다(client-인증서버 인증은 성공)
728x90
'스프링 시큐리티 OAuth2 > OAuth 2.0 Client - oauth2Client()' 카테고리의 다른 글
| DefaultOAuth2AuthorizedClientManager - Refresh Token 권한 부여 구현하기 (0) | 2023.02.22 |
|---|---|
| DefaultOAuth2AuthorizedClientManager - Client Credentials 권한 부여 구현하기 (0) | 2023.02.21 |
| DefaultOAuth2AuthorizedClientManager - Resource Owner Password 권한 부여 구현하기 (0) | 2023.02.20 |
| DefaultOAuth2AuthorizedClientManager (0) | 2023.01.29 |
| OAuth2ClientConfigurer 초기화 이해 (0) | 2023.01.27 |