Come usare OAuth2RestTemplate?

Sto cercando di capire come utilizzare un object OAuth2RestTemplate per consumare il mio servizio REST protetto OAuth2 (che è in esecuzione in un progetto diverso e assumiamo anche su un server diverso, ecc …)

Il mio servizio di rest è:

http://localhost:8082/app/helloworld 

-> L’accesso a questo URL genera un errore poiché non sono autenticato

Per richiedere un token vorrei andare a:

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

Dopo aver ricevuto il token posso quindi connettermi all’API REST utilizzando il seguente URL (esempio di token inserito)

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

Ora la mia domanda è: come posso implementare una seconda applicazione che può consumare questa API REST protetta OAuth2? Non ho davvero trovato esempi di lavoro in cui fornisci il nome utente e la password (ad esempio provenienti da un modulo di accesso) e poi viene generato un token che può essere riutilizzato per ottenere dati dall’API REST.

Al momento ho provato qualcosa con i seguenti oggetti:

 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); 

Ma questo non funziona 🙁

Qualsiasi idea è molto apprezzata o i collegamenti a esempi di lavoro e tutorial sono molto apprezzati.

Puoi trovare esempi per la scrittura di clienti Oauth qui https://github.com/spring-projects/spring-security-oauth

Nel tuo caso non puoi semplicemente usare le classi di base o di base per tutto, hai una class multipla Implementazione di OAuth2ProtectedResourceDetails. La configurazione dipende dal modo in cui hai configurato il tuo servizio Oauth, ma partendo dalle connessioni arricciate che consiglierei:

 @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 = new ResourceOwnerPasswordResourceDetails(); List scopes = new ArrayList(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(); } } 

Non dimenticare @ EnableOAuth2Client sulla tua class di configurazione, inoltre ti suggerirei di provare che gli URL che stai usando lavorano prima con il ricciolo, anche provare a rintracciarlo con il debugger perché molte eccezioni sono appena consumate e non vengono mai stampate a causa della sicurezza ragioni, quindi diventa difficile trovare il problema. È necessario utilizzare il logger con il set abilitato per il debug. In bocca al lupo

Ho caricato l’applicazione springboot di esempio su github https://github.com/mariubog/oauth-client-sample per descrivere la situazione perché non sono riuscito a trovare alcun campione per il tuo scenario.

Ho un approccio diverso se si desidera accedere a token ed effettuare chiamate ad altri sistemi di risorse con token di accesso nell’intestazione

Spring Security viene fornito con sicurezza automatica: accesso alle proprietà oauth2 dal file application.yml per ogni richiesta e ogni richiesta ha SESSIONID che legge e richiama le informazioni utente tramite Principal, quindi è necessario assicurarsi di iniettare Principal in OAuthUser e ottenere accessToken ed effettuare chiamate a server delle risorse

Questo è il tuo application.yml, cambia in base al tuo server di autenticazione:

 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 userDetail = new LinkedHashMap(); @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 detailMap = (LinkedHashMap) userAuthenticationToken.getDetails(); if (detailMap != null) { for (Map.Entry 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 getUserDetail() { return userDetail; } public void setUserDetail(Map 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 postCreateOrder_restTemplate(CreateOrder createOrder, OAuthUser oAuthUser) { String url_POST = "your post url goes here"; MultiValueMap 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 request = new HttpEntity(createOrder, headers); ResponseEntity result = restTemplate.exchange(url_POST, HttpMethod.POST, request, String.class); System.out.println("#### post response = " + result); return result; } } 

Nella risposta da @mariubog ( https://stackoverflow.com/a/27882337/1279002 ) stavo utilizzando anche i tipi di concessione della password come nell’esempio, ma era necessario impostare lo schema di autenticazione del client per la creazione. Gli ambiti non erano supportati dall’endpoint per la password e non era necessario impostare il tipo di concessione poiché l’object ResourceOwnerPasswordResourceDetails lo imposta automaticamente nel costruttore.

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

La cosa fondamentale per me era che client_id e client_secret non venivano aggiunti all’object modulo per postare nel corpo se resource.setClientAuthenticationScheme(AuthenticationScheme.form); non è stato impostato.

Vedi lo switch in: org.springframework.security.oauth2.client.token.auth.DefaultClientAuthenticationHandler.authenticateTokenRequest()

Infine, quando ci si connette all’endpoint di Salesforce, il token della password deve essere aggiunto alla password.

 @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(); } }