programing

OAuth2Rest Template 사용법?

megabox 2023. 9. 6. 21:59
반응형

OAuth2Rest Template 사용법?

OAuth2RestTemplate 개체를 사용하여 OAuth2 보안 REST 서비스를 사용하는 방법을 이해하려고 합니다(다른 프로젝트에서 실행 중이며 다른 서버에서도 실행된다고 가정해 보겠습니다).

REST 서비스의 예는 다음과 같습니다.

http://localhost:8082/app/helloworld

-> 이 URL에 액세스하면 인증되지 않아 오류가 발생합니다.

토큰을 요청하려면 다음 위치로 이동합니다.

http://localhost:8082/app/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=**USERNAME**&password=**PASSWORD**

토큰을 받은 후 다음 URL(토큰 삽입 예제)을 사용하여 REST API에 연결할 수 있습니다.

http://localhost:8082/app/helloworld/?access_token=**4855f557-c6ee-43b7-8617-c24591965206**

이제 제 질문은 이 OAuth2 보안 REST API를 사용할 수 있는 두 번째 애플리케이션을 어떻게 구현할 수 있을까요?사용자 이름과 비밀번호를 입력한 다음 REST API에서 데이터를 가져오는 데 다시 사용할 수 있는 토큰을 생성하는 작업 예를 찾을 수 없었습니다.

현재 다음 개체로 시도해 보았습니다.

BaseOAuth2ProtectedResourceDetails baseOAuth2ProtectedResourceDetails =  new BaseOAuth2ProtectedResourceDetails();
baseOAuth2ProtectedResourceDetails.setClientId("restapp");
baseOAuth2ProtectedResourceDetails.setClientSecret("restapp");
baseOAuth2ProtectedResourceDetails.setGrantType("password");
// how to set user name and password ???

DefaultAccessTokenRequest accessTokenRequest = new DefaultAccessTokenRequest();
OAuth2ClientContext oAuth2ClientContext = new DefaultOAuth2ClientContext(accessTokenRequest());

OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(baseOAuth2ProtectedResourceDetails,oAuth2ClientContext);

하지만 이건 그냥 안 돼요 :(

아이디어나 작업 예시 또는 튜토리얼에 대한 링크는 무엇이든 대단히 감사드립니다.

OAuth 클라이언트를 작성하는 예는 여기에서 찾을 수 있습니다.

클래스나 수 없는 . 구현 나 만 에 할 가 가 나 할 .OAuth2ProtectedResourceDetails 컬 로 할 때 다음을 OAuth 서비스를 구성한 방법에 따라 구성이 달라지지만 컬 연결을 전제로 할 때 다음을 권장합니다.

@EnableOAuth2Client
@Configuration
class MyConfig{

    @Value("${oauth.resource:http://localhost:8082}")
    private String baseUrl;
    @Value("${oauth.authorize:http://localhost:8082/oauth/authorize}")
    private String authorizeUrl;
    @Value("${oauth.token:http://localhost:8082/oauth/token}")
    private String tokenUrl;

    @Bean
    protected OAuth2ProtectedResourceDetails resource() {
        ResourceOwnerPasswordResourceDetails resource;
        resource = new ResourceOwnerPasswordResourceDetails();

        List scopes = new ArrayList<String>(2);
        scopes.add("write");
        scopes.add("read");
        resource.setAccessTokenUri(tokenUrl);
        resource.setClientId("restapp");
        resource.setClientSecret("restapp");
        resource.setGrantType("password");
        resource.setScope(scopes);
        resource.setUsername("**USERNAME**");
        resource.setPassword("**PASSWORD**");
        return resource;
    }

    @Bean
    public OAuth2RestOperations restTemplate() {
        AccessTokenRequest atr = new DefaultAccessTokenRequest();
        return new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(atr));
    }
}

@Service
@SuppressWarnings("unchecked")
class MyService {

    @Autowired
    private OAuth2RestOperations restTemplate;

    public MyService() {
        restTemplate.getAccessToken();
    }
}

ㅇ을 @EnableOAuth2Client구성 클래스에서 사용 중인 URL이 curl과 함께 작동하는 것을 먼저 시도하고, 많은 예외가 소비되고 적절한 보안상의 이유로 출력되지 않으므로 문제의 위치를 찾는 것이 거의 어렵기 때문에 디버거를 사용하여 추적해 보는 것도 좋습니다.당신은 사용해야 합니다.logger와 함께debugenabled set 입니다.행운을 빌어요

당신의 시나리오에 대한 샘플을 찾을 수 없었기 때문에 당신의 상황을 묘사하기 위해 github https://github.com/mariubog/oauth-client-sample 에 샘플 스프링부트 앱을 올렸습니다.

@markubog(https://stackoverflow.com/a/27882337/1279002) 의 답변에서는 예제에서와 같이 암호 부여 유형도 사용하고 있었지만 클라이언트 인증 체계를 형식으로 설정해야 했습니다.범위가 암호에 대한 끝점에서 지원되지 않으므로 ResourceOwnerPasswordResourceDetails 개체가 생성자에서 자체적으로 설정하므로 허용 유형을 설정할 필요가 없습니다.

...

public ResourceOwnerPasswordResourceDetails() {
    setGrantType("password");
}

...

저에게 핵심적인 것은 client_id와 client_secret가 본문에 게시할 폼 객체에 추가되지 않았다는 것입니다.resource.setClientAuthenticationScheme(AuthenticationScheme.form);설정되지 않았습니다.

스위치 참조:org.springframework.security.oauth2.client.token.auth.DefaultClientAuthenticationHandler.authenticateTokenRequest()

마지막으로 Salesforce Endpoint에 연결할 때 암호 토큰을 암호에 추가해야 합니다.

@EnableOAuth2Client
@Configuration
class MyConfig {

@Value("${security.oauth2.client.access-token-uri}")
private String tokenUrl;

@Value("${security.oauth2.client.client-id}")
private String clientId;

@Value("${security.oauth2.client.client-secret}")
private String clientSecret;

@Value("${security.oauth2.client.password-token}")
private String passwordToken;

@Value("${security.user.name}")
private String username;

@Value("${security.user.password}")
private String password;


@Bean
protected OAuth2ProtectedResourceDetails resource() {

    ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();

    resource.setAccessTokenUri(tokenUrl);
    resource.setClientId(clientId);
    resource.setClientSecret(clientSecret);
    resource.setClientAuthenticationScheme(AuthenticationScheme.form);
    resource.setUsername(username);
    resource.setPassword(password + passwordToken);

    return resource;
}

@Bean
 public OAuth2RestOperations restTemplate() {
    return new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
    }
}


@Service
@SuppressWarnings("unchecked")
class MyService {
    @Autowired
    private OAuth2RestOperations restTemplate;

    public MyService() {
        restTemplate.getAccessToken();
    }
}

액세스 토큰을 사용하고 헤더에 액세스 토큰이 있는 다른 리소스 시스템으로 전화를 걸려면 다른 접근 방식을 사용합니다.

Spring Security에는 자동 보안 기능이 포함되어 있습니다. application.yml 파일에서 oauth2 properties 액세스가 가능하며 모든 요청에는 Principle을 통해 사용자 정보를 읽고 꺼내는 SESSIONID가 있으므로 Principle in OAuthUser를 주입하고 액세스를 받아야 합니다.토큰을 생성하여 리소스 서버로 호출

이것은 당신의 application.yml, 당신의 인증 서버에 따라 변경합니다.

security:
  oauth2:
    client:
      clientId: 233668646673605
      clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d
      accessTokenUri: https://graph.facebook.com/oauth/access_token
      userAuthorizationUri: https://www.facebook.com/dialog/oauth
      tokenName: oauth_token
      authenticationScheme: query
      clientAuthenticationScheme: form
    resource:
      userInfoUri: https://graph.facebook.com/me

@Component
public class OAuthUser implements Serializable {

private static final long serialVersionUID = 1L;

private String authority;

@JsonIgnore
private String clientId;

@JsonIgnore
private String grantType;
private boolean isAuthenticated;
private Map<String, Object> userDetail = new LinkedHashMap<String, Object>();

@JsonIgnore
private String sessionId;

@JsonIgnore
private String tokenType;

@JsonIgnore
private String accessToken;

@JsonIgnore
private Principal principal;

public void setOAuthUser(Principal principal) {
    this.principal = principal;
    init();
}

public Principal getPrincipal() {
    return principal;
}

private void init() {
    if (principal != null) {
        OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) principal;
        if (oAuth2Authentication != null) {
            for (GrantedAuthority ga : oAuth2Authentication.getAuthorities()) {
                setAuthority(ga.getAuthority());
            }
            setClientId(oAuth2Authentication.getOAuth2Request().getClientId());
            setGrantType(oAuth2Authentication.getOAuth2Request().getGrantType());
            setAuthenticated(oAuth2Authentication.getUserAuthentication().isAuthenticated());

            OAuth2AuthenticationDetails oAuth2AuthenticationDetails = (OAuth2AuthenticationDetails) oAuth2Authentication
                    .getDetails();
            if (oAuth2AuthenticationDetails != null) {
                setSessionId(oAuth2AuthenticationDetails.getSessionId());
                setTokenType(oAuth2AuthenticationDetails.getTokenType());

            // This is what you will be looking for 
                setAccessToken(oAuth2AuthenticationDetails.getTokenValue());
            }

    // This detail is more related to Logged-in User
            UsernamePasswordAuthenticationToken userAuthenticationToken = (UsernamePasswordAuthenticationToken) oAuth2Authentication.getUserAuthentication();
            if (userAuthenticationToken != null) {
                LinkedHashMap<String, Object> detailMap = (LinkedHashMap<String, Object>) userAuthenticationToken.getDetails();
                if (detailMap != null) {
                    for (Map.Entry<String, Object> mapEntry : detailMap.entrySet()) {
                        //System.out.println("#### detail Key = " + mapEntry.getKey());
                        //System.out.println("#### detail Value = " + mapEntry.getValue());
                        getUserDetail().put(mapEntry.getKey(), mapEntry.getValue());
                    }

                }

            }

        }

    }
}


public String getAuthority() {
    return authority;
}

public void setAuthority(String authority) {
    this.authority = authority;
}

public String getClientId() {
    return clientId;
}

public void setClientId(String clientId) {
    this.clientId = clientId;
}

public String getGrantType() {
    return grantType;
}

public void setGrantType(String grantType) {
    this.grantType = grantType;
}

public boolean isAuthenticated() {
    return isAuthenticated;
}

public void setAuthenticated(boolean isAuthenticated) {
    this.isAuthenticated = isAuthenticated;
}

public Map<String, Object> getUserDetail() {
    return userDetail;
}

public void setUserDetail(Map<String, Object> userDetail) {
    this.userDetail = userDetail;
}

public String getSessionId() {
    return sessionId;
}

public void setSessionId(String sessionId) {
    this.sessionId = sessionId;
}

public String getTokenType() {
    return tokenType;
}

public void setTokenType(String tokenType) {
    this.tokenType = tokenType;
}

public String getAccessToken() {
    return accessToken;
}

public void setAccessToken(String accessToken) {
    this.accessToken = accessToken;
}

@Override
public String toString() {
    return "OAuthUser [clientId=" + clientId + ", grantType=" + grantType + ", isAuthenticated=" + isAuthenticated
            + ", userDetail=" + userDetail + ", sessionId=" + sessionId + ", tokenType="
            + tokenType + ", accessToken= " + accessToken + " ]";
}

@RestController
public class YourController {

@Autowired
OAuthUser oAuthUser;

// In case if you want to see Profile of user then you this 
@RequestMapping(value = "/profile", produces = MediaType.APPLICATION_JSON_VALUE)
public OAuthUser user(Principal principal) {
    oAuthUser.setOAuthUser(principal);

    // System.out.println("#### Inside user() - oAuthUser.toString() = " + oAuthUser.toString());

    return oAuthUser;
}


@RequestMapping(value = "/createOrder",
        method = RequestMethod.POST,
        headers = {"Content-type=application/json"},
        consumes = MediaType.APPLICATION_JSON_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE)
public FinalOrderDetail createOrder(@RequestBody CreateOrder createOrder) {

    return postCreateOrder_restTemplate(createOrder, oAuthUser).getBody();
}


private ResponseEntity<String> postCreateOrder_restTemplate(CreateOrder createOrder, OAuthUser oAuthUser) {

String url_POST = "your post url goes here";

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.add("Authorization", String.format("%s %s", oAuthUser.getTokenType(), oAuthUser.getAccessToken()));
    headers.add("Content-Type", "application/json");

    RestTemplate restTemplate = new RestTemplate();
    //restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

    HttpEntity<String> request = new HttpEntity<String>(createOrder, headers);

    ResponseEntity<String> result = restTemplate.exchange(url_POST, HttpMethod.POST, request, String.class);
    System.out.println("#### post response = " + result);

    return result;
}


}

내 간단한 해결책.임호가 제일 깨끗해요.

먼저 application.yml을 만듭니다.

spring.main.allow-bean-definition-overriding: true

security:
  oauth2:
    client:
      clientId: XXX
      clientSecret: XXX
      accessTokenUri: XXX
      tokenName: access_token
      grant-type: client_credentials

주 클래스 만들기: 클래스

@SpringBootApplication
@EnableOAuth2Client
public class Main extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/").permitAll();
    }

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @Bean
    public OAuth2RestTemplate oauth2RestTemplate(ClientCredentialsResourceDetails details) {
        return new OAuth2RestTemplate(details);
    }

}

그런 다음 Create controller class:컨트롤러

@RestController
class OfferController {

    @Autowired
    private OAuth2RestOperations restOperations;

    @RequestMapping(value = "/<your url>"
            , method = RequestMethod.GET
            , produces = "application/json")
    public String foo() {
        ResponseEntity<String> responseEntity = restOperations.getForEntity(<the url you want to call on the server>, String.class);
        return responseEntity.getBody();
    }
}

메이븐 종속성

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.5.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security.oauth.boot</groupId>
        <artifactId>spring-security-oauth2-autoconfigure</artifactId>
        <version>2.1.5.RELEASE</version>
    </dependency>
</dependencies>

언급URL : https://stackoverflow.com/questions/27864295/how-to-use-oauth2resttemplate

반응형