• 0
KLÉBERM

Integração da API do MercadoLivre com o Spring-Security

Question

Alguém já tentou e conseguiu integrar a API do MercadoLivre com o Spring-Security? Estou tentando fazer isso em meu projeto atual, para que o processo de autorização com o site do MercadoLivre seja executado de dentro do processo de autenticação do Spring-Security, e os dados de usuário e de compras efetuados possam ficar "salvo" no contexto do Spring, de modo que eu possa acessar essas informações usando uma chamada como ((UseRresponse) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).<método da classe UserResponse). Alguém saberia como fazer isso?

 

Os métodos principais, onde tudo isso deve ser executado, são:

 

Security.java

@Configuration
@EnableWebSecurity
public class Security extends WebSecurityConfigurerAdapter {
  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return new AuthenticationManager() {
      @Override
    	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    		return new Authentication() {
          public Collection<? extends GrantedAuthority> 	getAuthorities() {
            return null;
          }

          public Object 	getCredentials() {
            return null;
          }

          public Object 	getDetails() {
            return null;
          }

          public Object 	getPrincipal() {
            return null;
          }

          public boolean 	isAuthenticated() {
            return true;
          }

          public void 	setAuthenticated(boolean isAuthenticated) {}

          public String getName() {
            return null;
          }
        };
    	}
    };
  }

  @Override
  public void configure(HttpSecurity http) throws Exception {
      http
        .csrf().disable()
        .authorizeRequests()
          .antMatchers("/css/**", "/images/**", "/js/**", "/**").permitAll()
          .anyRequest().authenticated()
        .and()
        .formLogin()
          .loginPage("/login")
          .loginProcessingUrl("/doLogin")
        .and()
        .logout()
          .logoutUrl("/logout");
  }

  @Override
  public void configure(WebSecurity web) throws Exception {
    DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
    handler.setPermissionEvaluator(new PermissionEvaluator() {
      public boolean hasPermission(org.springframework.security.core.Authentication authentication, java.io.Serializable targetId, java.lang.String targetType, java.lang.Object permission) {
        if (authentication == null || !authentication.isAuthenticated())
          return false;
        else
          for(GrantedAuthority authority: authentication.getAuthorities())
            if(authority.getAuthority().equals(permission))
              return true;
        return false;
      }

      public boolean hasPermission(org.springframework.security.core.Authentication authentication, java.lang.Object targetDomainObject, java.lang.Object permission) {
        if (authentication == null || !authentication.isAuthenticated())
          return false;
        else
          for(GrantedAuthority authority: authentication.getAuthorities())
            if(authority.getAuthority().equals(permission))
              return true;
        return false;
      }
    });
    web.expressionHandler(handler);
  }
}

MercadoLivre.java

public class MercadoLivre {
    Long clientId = 0L;
    String clientSecret = "...";
    String redirectUri = "http://localhost:8080/";
    String accessToken;

    private DefaultApi api = new DefaultApi(new ApiClient(), clientId, clientSecret);

    public String getAuthUrl() throws Exception {
      return api.getAuthUrl(redirectUri, Configuration.AuthUrls.MLB);
    }

    public AccessToken getAccessToken(String code) throws Exception {
      AccessToken response = api.authorize(code, redirectUri);
      accessToken = response.getAccess_token();
      return response;
    }

    public RefreshToken refreshToken(String refreshToken) throws Exception {
      return api.refreshAccessToken(refreshToken);
    }

    public Object GET(String resource) throws ApiException {
      return api.defaultGet(resource);
    }

    public Object POST(String resource, String body) throws ApiException {
      return api.defaultPost(accessToken, resource, body);
    }

    public Object PUT(String resource, String id, String body) throws ApiException {
      return api.defaultPut(resource, id, accessToken, body);
    }

    public Object DELETE(String resource, String id) throws ApiException {
      return api.defaultDelete(resource, id, accessToken);
    }

    public UserResponse getUser() throws ApiException {
      return (UserResponse) GET("/users/me");
    }

}

 

 

Share this post


Link to post
Share on other sites

11 answers to this question

Recommended Posts

  • 0
13 hours ago, KLÉBERM said:

Alguém já tentou e conseguiu integrar a API do MercadoLivre com o Spring-Security? Estou tentando fazer isso em meu projeto atual, para que o processo de autorização com o site do MercadoLivre seja executado de dentro do processo de autenticação do Spring-Security, e os dados de usuário e de compras efetuados possam ficar "salvo" no contexto do Spring, de modo que eu possa acessar essas informações usando uma chamada como ((UseRresponse) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).<método da classe UserResponse). Alguém saberia como fazer isso?

 

não trabalho com JAVA e particularmente sou contra o uso de frameworks (em 99% dos casos)... mas, acho que você está confundindo um pouco os conceitos: o Spring-Security é para criar segurança para o SEU aplicativo, a autenticação do usuário no seu aplicativo não tem nenhuma relação com a da API (inclusive você nunca vai ter os dados de autenticação do seu usuário no ML) , a API já tem seu próprio método de autenticação, que é o oAuth2.0

Share this post


Link to post
Share on other sites
  • 0

O que eu queria era somente que o processo de autorização com o ML fosse executado de dentro do processo de login do Spring-Security: os passos descritos neste link, por exemplo:

https://developers.mercadolivre.com.br/pt_br/autenticacao-e-autorizacao#Server-side

que basicamente envolvem acessar a url

https://auth.mercadolibre.com.ar/authorization?response_type=code&client_id=$APP_ID

e no final ser direcionado para a url de retorno da aplicação

http://YOUR_REDIRECT_URI?code=SERVER_GENERATED_AUTHORIZATION_CODE

com o código necessário para gerar o accessToken.

Estou procurando uma maneira de executar todos esses passos dentro do método

public Authentication authenticate(Authentication authentication)

que fica na classe de configuração do Spring-Security. De modo que quando o usuário clicasse em um botão "efetuar login" na página inicial da aplicação, seja direcionado para a url de autorização, e quando retornasse para a aplicação, já seria mostrada uma página personalizada para ele.

Será que teria algum forma de conseguir algo parecido com isso?

Share this post


Link to post
Share on other sites
  • 0
1 hour ago, KLÉBERM said:

O que eu queria era somente que o processo de autorização com o ML fosse executado de dentro do processo de login do Spring-Security: os passos descritos neste link, por exemplo:

https://developers.mercadolivre.com.br/pt_br/autenticacao-e-autorizacao#Server-side

que basicamente envolvem acessar a url


https://auth.mercadolibre.com.ar/authorization?response_type=code&client_id=$APP_ID

e no final ser direcionado para a url de retorno da aplicação


http://YOUR_REDIRECT_URI?code=SERVER_GENERATED_AUTHORIZATION_CODE

com o código necessário para gerar o accessToken.

Estou procurando uma maneira de executar todos esses passos dentro do método


public Authentication authenticate(Authentication authentication)

que fica na classe de configuração do Spring-Security. De modo que quando o usuário clicasse em um botão "efetuar login" na página inicial da aplicação, seja direcionado para a url de autorização, e quando retornasse para a aplicação, já seria mostrada uma página personalizada para ele.

Será que teria algum forma de conseguir algo parecido com isso?

precisa estudar mais!! como sempre digo: tem que entender os conceitos, dominar a linguagem, só depois ir para a prática... você quer fazer algo mais "complexo"mas está pulando os passos básicos (na realidade é bem simples, mas tem que entender como as coisas funcionam) ...

para início compreenda como funciona o oAuth2.0 ... se você vai usar uma autenticação server-side então não tem lógica autenticar o usuário no ML toda vez que o usuário logar na sua aplicação... isso você vai controlar no seu backend e guardar os tokens em um DB, como te disse o Spring-Security vai realizar o controle de acesso ao seu aplicativo... 

Share this post


Link to post
Share on other sites
  • 0
Quote

 se você vai usar uma autenticação server-side então não tem lógica autenticar o usuário no ML toda vez que o usuário logar na sua aplicação

Não é isso que eu quero fazer.

Quote

isso você vai controlar no seu backend e guardar os tokens em um DB

Isso está mais próximo do que eu quero.

Eu já desenvolvi outros projetos que usavam Spring-Security com acesso à banco de dados (normalmente eu nem uso um AuthenticationManager personalizado para isso, prefiro toda a configuração em uma classe de configuração única). Só preciso acrescentar agora essa parte de encaminhar o usuário para uma URL externa e quando o fluxo da autorização retornar para minha aplicação, retornar ao ponto de onde o encaminhamento externo foi realizado.

 

Qualquer dica de como eu poderia fazer isso seria bem vinda.

Share this post


Link to post
Share on other sites
  • 0

Códigos atualizados:

MercadoLivre.java

public class MercadoLivre {
    Long clientId = 0L;
    String clientSecret = "abc123";
    String redirectUri = "https://localhost:8080/";
    String accessToken;
    String refreshToken;

    private DefaultApi api = new DefaultApi(new ApiClient(), clientId, clientSecret);

    private String getAuthUrl() throws Exception {
      return api.getAuthUrl(redirectUri, Configuration.AuthUrls.MLB);
    }

    private AccessToken getAccessToken(String code) throws Exception {
      AccessToken response = api.authorize(code, redirectUri);
      accessToken = response.getAccess_token();
      return response;
    }

    private RefreshToken refreshToken() throws Exception {
      RefreshToken response = api.refreshAccessToken(refreshToken);
      accessToken = response.getAccess_token();
      refreshToken = response.getRefresh_token();
      return response;
    }

    public Object GET(String resource) throws ApiException {
      return api.defaultGet(resource);
    }

    public Object POST(String resource, String body) throws ApiException {
      return api.defaultPost(accessToken, resource, body);
    }

    public Object PUT(String resource, String id, String body) throws ApiException {
      return api.defaultPut(resource, id, accessToken, body);
    }

    public Object DELETE(String resource, String id) throws ApiException {
      return api.defaultDelete(resource, id, accessToken);
    }

    public UserResponse getUser() {
      try {
          UserResponse result = api.usersMeGet(accessToken);
          System.out.println(result);
          return result;
      } catch (ApiException e) {
          System.err.println("Exception when calling DefaultApi#usersMeGet");
          e.printStackTrace();
          return null;
      }
    }
}

Security.java

@Configuration
@EnableWebSecurity
public class Security extends WebSecurityConfigurerAdapter {
  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return new AuthManager();
  }

  @Override
  public void configure(HttpSecurity http) throws Exception {
      http
        .csrf().disable()
        .authorizeRequests()
          .antMatchers("/css/**", "/images/**", "/js/**", "/**").permitAll()
          .anyRequest().authenticated()
        .and()
        .formLogin()
          .loginPage("/login").permitAll()
          .loginProcessingUrl("/doLogin").permitAll()
        .and()
        .logout()
          .logoutUrl("/logout");
  }

  @Override
  public void configure(WebSecurity web) throws Exception {
    DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
    handler.setPermissionEvaluator(new PermissionEvaluator() {
      public boolean hasPermission(org.springframework.security.core.Authentication authentication, java.io.Serializable targetId, java.lang.String targetType, java.lang.Object permission) {
        if (authentication == null || !authentication.isAuthenticated())
          return false;
        else
          for(GrantedAuthority authority: authentication.getAuthorities())
            if(authority.getAuthority().equals(permission))
              return true;
        return false;
      }

      public boolean hasPermission(org.springframework.security.core.Authentication authentication, java.lang.Object targetDomainObject, java.lang.Object permission) {
        if (authentication == null || !authentication.isAuthenticated())
          return false;
        else
          for(GrantedAuthority authority: authentication.getAuthorities())
            if(authority.getAuthority().equals(permission))
              return true;
        return false;
      }
    });
    web.expressionHandler(handler);
  }
}

AuthManager.java (é daqui que queria direcionar o usuário para a URL externa para autenticação com o ML e no retorno, e também para onde a aplicação deveria retornar após esse passo).

public class AuthManager implements AuthenticationManager {
  @Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    System.out.println("AuthManager.authenticate()");
    MercadoLivre mercadoLivre = new MercadoLivre();
    //código desejado aqui
		return new AuthResponse(mercadoLivre.getUser());
	}
}

AuthResponse.java

public class AuthResponse implements Authentication {
  private UserResponse user;

  public AuthResponse(UserResponse user) {
    this.user = user;
  }

  public Collection<? extends GrantedAuthority>	getAuthorities() {
    return null;
  }

  public Object	getCredentials() {
    return user.getEmail();
  }

  public Object	getDetails() {
    return user.getStatus();
  }

  public Object	getPrincipal() {
    return user;
  }

  public boolean	isAuthenticated() {
    return true;
  }

  public void	setAuthenticated(boolean isAuthenticated) {
    //
  }

  public String getName() {
    return user.getFirstName() + " " + user.getLastName();
  }
}

 

 

Share this post


Link to post
Share on other sites
  • 0
1 hour ago, KLÉBERM said:

Não é isso que eu quero fazer.

Isso está mais próximo do que eu quero.

Eu já desenvolvi outros projetos que usavam Spring-Security com acesso à banco de dados (normalmente eu nem uso um AuthenticationManager personalizado para isso, prefiro toda a configuração em uma classe de configuração única). Só preciso acrescentar agora essa parte de encaminhar o usuário para uma URL externa e quando o fluxo da autorização retornar para minha aplicação, retornar ao ponto de onde o encaminhamento externo foi realizado.

 

Qualquer dica de como eu poderia fazer isso seria bem vinda.

você não está entendendo como funciona o oAuth2.0 e está se confundindo muito nos conceitos... você diz que não é o que quer fazer, mas na prática é exatamente o que está fazendo... o nome já diz tudo: "server-side"

Share this post


Link to post
Share on other sites
  • 0

Esse codigo funciona para voce ?

Unirest.setTimeouts(0, 0);
HttpResponse<String> response = Unirest.post("https://api.mercadolibre.com/oauth/token")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .field("client_id", "")
  .field("client_secret", "")
  .field("grant_type", "client_credentials")
  .asString();

Share this post


Link to post
Share on other sites
  • 0

Eu alterei meu projeto para usar a biblioteca spring-oauth2. Ficou assim a configuração:

application.properties:

spring.security.oauth2.client.registration.mercadolivre=mercadolivre
spring.security.oauth2.client.registration.mercadolivre.client-id=...
spring.security.oauth2.client.registration.mercadolivre.client-secret=...
spring.security.oauth2.client.registration.mercadolivre.client-authentication-method=post
spring.security.oauth2.client.registration.mercadolivre.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.mercadolivre.redirect-uri=http://localhost:8080
spring.security.oauth2.client.provider.mercadolivre.authorization-uri=https://auth.mercadolivre.com.br/authorization
spring.security.oauth2.client.provider.mercadolivre.token-uri=https://auth.mercadolivre.com.br/oauth
spring.security.oauth2.client.provider.mercadolivre.user-info-uri=https://api.mercadolibre.com/users/me
spring.security.oauth2.client.provider.mercadolivre.user-info-authentication-method=form
spring.security.oauth2.client.provider.mercadolivre.userNameAttribute=usuario

spring-security configuration class:

@Configuration
@EnableWebSecurity
@EnableOAuth2Sso
public class Security extends WebSecurityConfigurerAdapter {
  @Override
  public void configure(HttpSecurity http) throws Exception {
      http
        .csrf().disable()
        .authorizeRequests()
          .antMatchers("/css/**", "/images/**", "/js/**", "/**").permitAll()
          .anyRequest().authenticated()
        .and()
        .formLogin()
          .loginPage("/login")
          .loginProcessingUrl("/doLogin").permitAll()
        .and()
        .oauth2Login()
        .and()
        .logout()
          .logoutUrl("/logout");
  }
...
}

html:

<body>
    <ul>
      <li class="right" sec:authorize="isAnonymous()">
        <a class="button" th:href="@{/oauth2/authorization/mercadolivre}">Entrar</button>
      </li>

      <li sec:authorize="isAuthenticated()">
        Logged in as: <span sec:authentication="name">Bob</span>
      </li>

      <li class="right" sec:authorize="isAuthenticated()">
        <a class="button" th:href="@{/logout}">Sair</button>
      </li>
    </ul>
</body>

com ess código, quando eu clico no link de login, sou direcionado para a página de autorização do mercadolivre corretamente, e retorno ao finalizar o procedimento para a página de redirecionamento de minha aplicação. Na URL de retorno, o código para obtenção do accessToken vem anexado corretamente, mas nada de autenticação (página é mostrada como se estivesse sendo acessada anonimamente).

Share this post


Link to post
Share on other sites
  • 0

autenticacao oauth2 != autenticacao no mercado livre

se tua intenção é mostrar paginas do mercado livre no seu app simplesmente navegue pela pagina com um ACTION_VIEW

oauth2 tu usa para interagir pela plataforma de modo não visual

Share this post


Link to post
Share on other sites
  • 0

Eu nao quero mostrar página do ML na aplicação (não é uma aplicação mobile, é web). Meu objetivo é, após o login, fazer um batimento de produtos cadastrados na aplicação com produtos comprados através do mercado livre. Dependendo desse batimento, seria mostrado box com opções diferentes para cada produto (por exemplo, se não tiver sido comprado, será mostrado um botão com link para a página dele no mercado livre, se tiver sido comprado, mostrará outras opções relativas ao pós venda).

Share this post


Link to post
Share on other sites
  • 0
36 minutes ago, KLÉBERM said:

Eu nao quero mostrar página do ML na aplicação (não é uma aplicação mobile, é web). 

em algum momento você terá que mostrar a página do ML, que é a de autorização

37 minutes ago, KLÉBERM said:

Meu objetivo é, após o login, fazer um batimento de produtos cadastrados na aplicação com produtos comprados através do mercado livre.

comprados ou vendidos? a API é voltada para vendas (usuário vendedor/loja)

38 minutes ago, KLÉBERM said:

Dependendo desse batimento, seria mostrado box com opções diferentes para cada produto (por exemplo, se não tiver sido comprado, será mostrado um botão com link para a página dele no mercado livre, se tiver sido comprado, mostrará outras opções relativas ao pós venda).

isso é algo bem simples de ser feito (em qualquer linguagem)...

você consegue fazer a autenticação sem o Spring-Security? pois antes de usar o framework você tem que saber fazer a autenticação "pura"

caso já consiga fazer a autenticação, então a questão é ler toda a documentação do Spring-Security (o que inclui ler todos os arquivos de código fonte dele), pois nesse caso é falta de entendimento de como o framework funciona, e não tem relação com este forum que é referente a API do ML

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now