======= API.sistemas- API de Serviços da UFRN =======
=====O que é a API.sistemas?=====
É um canal de comunicação que tem como principal função disponibilizar os dados dos sistemas da UFRN
para que seja possível proporcionar que entidades externas criem aplicações(independentes de plataforma)
que utilizam tais dados. Os dados são disponibilizados no formato JSON, para ser de fácil consumação pelos
usuários e aplicações serem independentes de plataforma e linguagem de programação.
=====Tecnologias utilizadas=====
==== OAuth 2.0 ====
No intuito de possibilitar a utilização dos dados gerados nos seus sistemas, grandes empresas desenvolveram protocolos de autorização proprietários para permitir a criação de aplicações que acessassem suas APIs. A criação desses novos protocolos deve-se ao fato de que no modelo tradicional cliente-servidor o usuário precisa compartilhar suas credenciais com as aplicações para permitir que as mesmas utilizem seus dados, o que gera problemas de segurança, pois aplicações mal intencionadas poderiam utilizar a senha do usuário para acessar indevidamente os dados do mesmo.
Entretanto, a criação de protocolos de autorização proprietários adicionou um custo, em razão de que um desenvolvedor precisaria aprender a implementar múltiplos protocolos para integrar diferentes provedores de APIs em sua(s) aplicação(ões). O //Open Authorization Protocol// (OAuth) surgiu como uma alternativa a isso, aparecendo como um protocolo de autorização aberto que objetiva padronizar a forma como aplicações acessam uma API para utilizar os dados do usuário.
O OAuth 2.0 é uma evolução do protocolo OAuth e busca simplificar o desenvolvimento dos clientes provendo fluxos de autorização específicos para aplicações //web//, //desktop//, //mobile// e outros dispositivos.
== Conceitos importantes ==
* **Autenticação**: processo de verificar a identidade de um usuário, em outras palavras, é o processo que verifica se um usuário é quem ele diz ser.
* **Autenticação federada**: aplicações que dependem de outros serviços para verificar a identidade de usuários.
* **Autorização**: processo de verificar se o usuário tem o direito de executar uma ação.
* **Autorização delegada**: processo no qual o usuário concede permissão para uma pessoa ou aplicação realizar ações em seu nome.
== Papéis ==
* //Resource owner//: entidade que tem a capacidade de conceder acesso a recursos protegidos.
* //Resource server//: entidade que disponibiliza o recurso protegido.
* //Client//: entidade que requisita o acesso ao recurso protegido.
* //Authorization server//: entidade que autoriza clientes a acessar recursos protegidos.
== Parâmetros importantes ==
* //client_id//: sequência única de caracteres que representa a identificação do cliente.
* //client_secret//: sequência de caracteres que representa a “senha” do cliente.
* //access_token//: sequência de caracteres que representam credenciais utilizadas para acessar recursos protegidos.
* //refresh_token//: sequência de caracteres utilizadas para requisitar um novo //access_token//.
* //redirect_uri//: página para onde o usuário deve ser redirecionado após a realização do login.
* //response_type//: Deve assumir os valores: "code" para requisitar //authorization code// ou "token" para requisitar um //access token// no fluxo //Implicit//.
* //grant_type//: Deve assumir os valores: 1) "authorization_code" no fluxo //Authorization code//; 2) "password" no fluxo //Resource Owner Password Credentials//; 3) "client_credentials" no fluxo //Client Credentials//; 4) "refresh_token" para requisitar um novo //token// de acesso.
* //token_type//: tipo do //token// gerado.
* //expires_in//: tempo de duração, em segundos, do //access_token//.
* //scope//: define o escopo de acesso.
* //username//: //login// do //resource owner//.
* //password//: senha do //resource owner//.
* //code//: //authorization code// enviado pelo //authorization server//.
== Fluxos de autorização ==
* //Authorization code//
Neste fluxo, o //client// redireciona o //resource owner// para que o mesmo realize autenticação no //authorization server// e, em seguida, autorize o //client// a utilizar seus recursos. Após o processo de autorização da aplicação, o //authorization server// envia um //authorization code// ao //client//.
Em posse do código, o //client// requisita um //access token// passando o código recebido. O //authorization server// verifica o código e envia um //access_token// e um //refresh_token// ao //client//. Por fim, o //client// requisita os dados do //resource server// passando o //access token// recebido do //authorization server//.
{{ :desenvolvimento:especificacoes:barramento_servicos:authorization_code.png?600 |}}
* //Implicit//
O fluxo de autorização implícito é uma simplificação do //authorization code//. Nele o //access token// é retornado ao //client// logo após o //resource owner// autorizá-lo a utilizar seus dados. E, em seguida, o //client// já pode requisitar os dados do recurso desejado no //resource server//.
Nesse fluxo não há suporte para //refresh token// e, caso o //access token// criado para o //resource owner// expire, o fluxo de autorização precisa ser repetido para requisitar um novo //access token//.
{{ :desenvolvimento:especificacoes:barramento_servicos:implict.png?500 |}}
* //Resource Owner Password Credentials//
Neste fluxo o //resource owner// informa seu //username// e //password// ao //client//, esse último usa essas informações para obter um //access token// do //authorization server//. Em posse, desse //token// o //client// já pode requisitar dados do //resource server//.
Esse tipo de fluxo é recomendado somente no caso em que a aplicação é propriedade do desenvolvedor da API, isso se deve em virtude de o //resource owner// precisar informar suas credenciais ao //client//.
{{ :desenvolvimento:especificacoes:password.png?500 |}}
* //Client Credentials//
Neste fluxo a aplicação envia suas credenciais ao //authorization server// e recebe um //access token// do mesmo. No fluxo //client credentials// não há suporte para //refresh token//, assim, quando o //token// expira a aplicação deve repetir o fluxo para obter um novo //access token//.
{{ :desenvolvimento:especificacoes:client_credentials.png?400 |}}
=== REST ===
REST do inglês Representational State Transfer, em português Transferência de Estado Representacional. Trata-se de um modelo arquitetural que possui um conjunto de restrições aplicados a todo o sistema web, como: componentes, conectores e elementos
de dados dentro de um sistema de hipermídia distribuído. É dispensável para essa tecnologia a sintaxe de implementação, já que pode ser aplicado em qualquer serviço web. Este que pode ser chamado de RESTful, caso atenda todas as restrições desse
padrão de arquitetura. Essas restrições estão divididas em seis partes, são elas:
* //Cliente-Servidor(Client-Server)//: Aqui traz-se o conceito de independência, onde existe separação entre o cliente e o servidor, o qual permite que servidores e clientes possam ser desenvolvidos independentemente sem que a comunicação entre eles sejam prejudicadas.
* //Sem Estado (Stateless)//: Como próprio nome já diz, trata-se de uma comunicação sem estado, ou seja, o servidor não guarda nenhum estado de sessão do cliente, de forma que todo dado é obtido com as informações da requisição, trazendo assim mais visibilidade, segurança e escalabilidade.
* //Cacheable//: A arquiteura REST permite que utilize-se serviços de armazenamento em cache das respostas dos servidores, porém é preciso trata-las para que os usuários não acessem dados obsoletos ou inapropriados. E um bom serviço de gerenciamento do cache pode trazer bastante eficiência nas comunicações com o servidor, já que muitas delas podem ser aproveitadas devido aos dados armazenados em cache.
* //Sistema em Camadas (Layered System)//: O sistema em camadas permite que o sistema seja dividido em camadas com restrições, de modo que cada componente da aplicação só possa ter acesso direto com as camadas de sua ligação. Isso com o intuito de melhorar as requisições do usuário, de modo de seja mais filtrada e direcionada da forma mais segura possível.
* //Interface Uniforme (Uniform Interface)//: Principal característica da arquitetura REST que foi designada para ser eficiente com grande numero de dados, trabalhando com um resultado equivalente apenas para a sua arquitetura. Existindo algumas estrições principais: as identificações de recursos que são identificadas na requisição, como as URI's; mensagens auto-descritivas onde cada mensagem possui toda a informação necessária para ser processada e hipermídia, o qual os clientes fazem transições de estado somente através de ações que são dinamicamente identificadas, por exemplo, hiperlinks em hipertextos.
=== JSON ===
Trata-se de uma modelagem de armazenamento de transmissão de arquivos de texto, oriundo do JavaScript, por isso significa JavaScript Obect Notation, mas que pode ser utilizado por diversas linguagens. É bastante simples, porém muito eficiente e poderoso, pois devido a sua forma compacta a sua transmissão e o 'parsing' da informação ocorrem de forma ágil. Algumas empresas já utilizam esse mecanismo, como a Google e a Yahoo, o que demonstra ser bastante eficientes, pois os dois trabalham com buscas e essa se trata de uma das melhores formas de se veicular a informação.
Cada informação é definido por uma tupla, sendo um rótulo e o seu valor, podendo ser este valor campos string, inteiros, reais, booleanos, arranjos e objetos.
Ex.:
{
“nome” : “Vinícius”,
“idade” : 21,
“altura” : 1.7,
“estudante” : true,
“interesses” : [“Development”, “Mobile”, “Web”, “Games”],
“parentes” : [
{
“nome” : “José”,
“parentesco” : “pai”
},
{
“nome” : “Maria”,
“parentesco” : “mãe”
}
]
}
=====Autorização e autenticação na API=====
Atualmente, a API de serviços da SINFO implementa e disponibiliza três dos quatro fluxos de autorização do OAuth 2.0 e o fluxo de //refresh_token//, os quais são mostrado abaixo.
===Client Credentials===
Esse fluxo foi implementado para ser usado por aplicações que queiram acessar os dados públicos dos sistemas da SINFO, com por exemplo: eventos, notícias, telefones, entre outros. Desse modo, aplicações com esse intuito, devem seguir os seguintes passos:
- A aplicação faz uma requisição POST ao //authorization server// através da URL http://apitestes.info.ufrn.br/authz-server/oauth/token, passando o //client_id//, //client_secret// e //grant_type// como //QueryParam//. Ex: **POST** http://apitestes.info.ufrn.br/authz-server/oauth/token?client_id=AppId&client_secret=AppSecret&grant_type=client_credentials
- O //authorization server// retorna à aplicação um //Json// contendo o //access_token//, //token_type//, //expires_in// e //scope//. Ex: { “access_token”: “000000000000000000000000000000000000”, “token_type”: “bearer”, “expires_in”: 7431095, “scope”: “read” }
- Em posse dessas informações, a aplicação já pode acessar os dados disponibilizados pela API passando o //token// através do parâmetro //Authorization// no //HEADER// da requisição desejada. Ex: **GET** http://apitestes.info.ufrn.br/telefone-services/services/consulta/telefone/ccet **Authorization**: Bearer 000000000000000000000000000000000000
- Os dados da API são retornados para a aplicação. Ex.:
[
{
"idTelefone": 0,
"localizacao": "string",
"setor": "string",
"descricao": "string",
"numero": "string",
"ramais": [
{
"numero": "string",
"descricao": "string"
}
]
}
]
{{ :desenvolvimento:especificacoes:client_credentials_ufrn.png?600 |}}
===Authorization code===
Esse fluxo deve ser utilizado por aplicações que queiram acessar as informações privadas às contas de usuários dos sistemas SINFO, como por exemplo: turmas de um usuário, frequências de um discente, histórico de utilização de um usuário no restaurante universitário, etc. Assim, aplicações com esse propósito precisam seguir os seguintes passos:
- O usuário inicia a interação com a aplicação.
- A aplicação faz uma requisição **GET** ao //authorization server// através da URL http://apitestes.info.ufrn.br/authz-server/oauth/authorize, passando os parâmetros //client_id//, //response_type// e //redirect_uri// como //QueryParam//. Ex: **GET** http://apitestes.info.ufrn.br/authz-server/oauth/authorize?client_id=AppId&response_type=code&redirect_uri=http://enderecoapp.com.br/pagina
- O usuário é redirecionado para o //authorization server//, o mesmo deve informar suas credenciais (//username//, //password//) na página de autenticação exibida e, em seguida, informar se autoriza a aplicação a utilizar seus dados.
- O //authorization server// retorna o código de autorização à aplicação.
- Em posse desse código, a aplicação pode usá-lo para obter um //access_token// para o usuário. Desse modo, ela realiza uma nova requisição, neste caso um **POST**, ao //authorization_server// através da URL http://apitestes.info.ufrn.br/authz-server/oauth/token, passando os parâmetros //client_id//, //client_secret//, //redirect_uri//, //grant_type// e //code// como //QueryParam//. Ex: **POST** http://apitestes.info.ufrn.br/authz-server/oauth/token?client_id=AppId&client_secret=AppSecret&redirect_uri=http://enderecoapp.com.br/pagina&grant_type=authorization_code&code=code
- O authorization server retorna à aplicação um //Json// contendo o //access_token//, //token_type//, //refresh_token//, //expires_in// e //scope//. Ex: { “access_token”: “000000000000000000000000000000000000”, “token_type”: “bearer”, "refresh_token": "ffffffffffffffffffffffffffffffffffff" , “expires_in”: 7431095, “scope”: “read” }
- - Em posse dessas informações, a aplicação já pode acessar os dados disponibilizados pela API passando o //token// através do parâmetro //Authorization// no //header// da requisição desejada. Ex: **GET** http://apitestes.info.ufrn.br/ensino-services/services/consulta/listavinculos/usuario **Authorization**: Bearer 000000000000000000000000000000000000
- Os dados da API são retornados para a aplicação. Ex.:
{
"docentes": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false,
"siape": "string",
"lotacao": "string"
}
],
"discentes": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false,
"matricula": "string",
"curso": "string",
"status": 0,
"anoIngresso": 0,
"periodoIngresso": 0
}
],
"docentesExterno": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false,
"matricula": "string",
"instituicao": "string"
}
],
"outros": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false
}
],
"id": 0,
"all": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false
}
]
}
{{ :desenvolvimento:especificacoes:authorization_code_ufrn.png?600 |}}
===Resource Owner Password Credentials===
Esse tipo de fluxo deve ser utilizado por aplicações que sejam de propriedade da própria SINFO e que necessitem dos dados privados a contas de usuários, em virtude de o OAuth 2.0 definir que no //Resource Owner Password Credentials// o usuário informa suas credenciais diretamente à aplicação. Logo, aplicações com essa característica precisam seguir os seguintes passos:
- O usuário informa suas credenciais de acessso à aplicação (//username// e //password//).
- A aplicação faz uma requisição **POST** ao //authorization server// através da URL http://apitestes.info.ufrn.br/authz-server/oauth/token, passando os parâmetros //client_id//, //client_secret//, //grant_type//, //username// e //password//. Ex: **POST** http://apitestes.info.ufrn.br/authz-server/oauth/token?client_id=AppId&client_secret=AppSecret&grant_type=password&username=loginUsuario&password=senhaUsuario
- O authorization server retorna à aplicação um //Json// contendo o //access_token//, //token_type//, //refresh_token//, //expires_in// e //scope//. Ex: { “access_token”: “000000000000000000000000000000000000”, “token_type”: “bearer”, "refresh_token": "ffffffffffffffffffffffffffffffffffff" , “expires_in”: 7431095, “scope”: “read” }
- Em posse dessas informações, a aplicação já pode acessar os dados disponibilizados pela API passando o novo //token// através do parâmetro //Authorization// no //header// da requisição desejada. Ex: **GET** http://apitestes.info.ufrn.br/ensino-services/services/consulta/listavinculos/usuario **Authorization**: Bearer 000000000000000000000000000000000000
- Os dados da API são retornados para a aplicação. Ex.:
{
"docentes": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false,
"siape": "string",
"lotacao": "string"
}
],
"discentes": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false,
"matricula": "string",
"curso": "string",
"status": 0,
"anoIngresso": 0,
"periodoIngresso": 0
}
],
"docentesExterno": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false,
"matricula": "string",
"instituicao": "string"
}
],
"outros": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false
}
],
"id": 0,
"all": [
{
"contemTurmas": false,
"idUsuario": 0,
"numero": 0,
"id": 0,
"ordem": 0,
"ativo": false
}
]
}
{{ :desenvolvimento:especificacoes:password_ufrn.png?600 |}}
===Refresh Token===
O fluxo de //refresh token// deve ser utilizado quando o //access_token// de um usuário expira em aplicações que utilizem os fluxos de autorização //authorization code// e //resource owner password credentials// disponibilizados pela API de serviços da SINFO. Assim, as mesmas devem seguir os seguintes passos:
- A aplicação deve fazer uma requisição **POST** ao servidor de autorização através da URL http://apitestes.info.ufrn.br/authz-server/oauth/token, passando os parâmetros //client_id//, //client_secret//, //grant_type// e //refresh_token// como //QueryParam//. Ex: **POST** http://apitestes.info.ufrn.br/authz-server/oauth/token?client_id=AppId&client_secret=AppSecret&grant_type=refresh_token&refresh_token=ffffffffffffffffffffffffffffffffffff
- O //authorization server// retorna à aplicação um //Json// contendo o //access_token//, //token_type//, //refresh_token//, //expires_in// e //scope//. Ex: { “access_token”: “111111111111111111111111111111111111”, “token_type”: “bearer”, "refresh_token": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" , “expires_in”: 7431095, “scope”: “read” }
- Em posse dessas informações, a aplicação já pode acessar os dados disponibilizados pela API passando o //token// através do parâmetro //Authorization// no //header// da requisição desejada. Ex: **GET** http://apitestes.info.ufrn.br/telefone-services/services/consulta/telefone/ccet **Authorization**: Bearer 111111111111111111111111111111111111
- Os dados da API são retornados para a aplicação. Ex.:
[
{
"idTelefone": 0,
"localizacao": "string",
"setor": "string",
"descricao": "string",
"numero": "string",
"ramais": [
{
"numero": "string",
"descricao": "string"
}
]
}
]
{{ :desenvolvimento:especificacoes:refresh_token_ufrn.png?600 |}}
===== Exemplos de utilização =====
====Android utilizando Authorization code====
Neste exemplo mostra-se a utilização do fluxo de autorização //authorization code// em uma aplicação Android.
Desse modo, a primeira tela da aplicação contém as funcionalidades básicas da mesma (Logar, Obter dados e Sair). Como mostrado nos dois trechos de código que formam a mesma:
* //activity_main.xml//
* //content_main.xml//
* Tela inicial da aplicação
{{:desenvolvimento:especificacoes:1.png?200|}}
Essa tela é controlada pela classe //MainActivity// que implementa as devidas ações relacionadas aos botões de logar, obter dados e sair, conforme exibido no trecho de código abaixo:
* //MainActivity.java//
//imports omitidos
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
public void logar(View v) {
Intent i = new Intent(this, ResultActivity.class);
OAuthTokenRequest.getInstance().getTokenCredential(this,"http://apitestes.info.ufrn.br/authz-server","CLIENT-ID", "CLIENT-SECRET", i);
}
public void obterDados(View v){
Intent intent = new Intent(this, ResultActivity.class);
startActivity(intent);
}
//métodos omitidos
public void sair(View view) {
OAuthTokenRequest.getInstance().logout(this, "http://apitestes.info.ufrn.br/sso-server/logout");
}
}
Como se pode ver no código acima as requisições a API são realizadas por meio de um cliente OAuth implementado na classe //OAuthTokenRequest//, exibida abaixo. A mesma se encarrega de buscar as credenciais de acesso para o usuário (//getTokenCredential(...)//) e também de realizar as requisições aos recursos que o mesmo quer utilizar (//resourceRequest(...)//). Além disso, para que a mesma funcione é preciso colocar dependências para as bibliotecas [[https://github.com/wuman/android-oauth-client|Android OAuth Client Library (android-oauth-client)]] e para o [[https://github.com/mcxiaoke/android-volley|Android Volley]]
* //OAuthTokenRequest.java//
//imports omitidos
/**
* Created by Mario on 04/11/2015.
*/
public class OAuthTokenRequest {
private Credential credential;
private static OAuthTokenRequest oAuthTokenRequest;
private String clientId, clientSecret;
private OAuthManager oauth;
public static OAuthTokenRequest getInstance(){
if(oAuthTokenRequest == null)
oAuthTokenRequest = new OAuthTokenRequest();
return oAuthTokenRequest;
}
private OAuthTokenRequest() {
}
public Credential getTokenCredential(final Activity activity,String oauthServerURL, String clientId,String clientSecret, final Intent i){
this.clientId = clientId;
this.clientSecret = clientSecret;
AuthorizationFlow.Builder builder = new AuthorizationFlow.Builder(
BearerToken.authorizationHeaderAccessMethod(),
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
new GenericUrl(oauthServerURL +"/oauth/token"),
new ClientParametersAuthentication(clientId, clientSecret),
clientId,
oauthServerURL +"/oauth/authorize");
AuthorizationFlow flow = builder.build();
AuthorizationUIController controller = new DialogFragmentController(activity.getFragmentManager()) {
@Override
public String getRedirectUri() throws IOException {
//return "http://android.local/";
return "http://localhost/Callback";
}
@Override
public boolean isJavascriptEnabledForWebView() {
return true;
}
};
oauth = new OAuthManager(flow, controller);
try {
OAuthManager.OAuthCallback callback = new OAuthManager.OAuthCallback() {
@Override public void run(OAuthManager.OAuthFuture future) {
try {
credential = future.getResult();
activity.startActivity(i);
} catch (IOException e) {
e.printStackTrace();
}
// make API queries with credential.getAccessToken()
}
};
oauth.authorizeExplicitly("userId", callback, null);
if(credential != null){
Log.d("TOKEN", credential.getAccessToken());
}
} catch (Exception e) {
e.printStackTrace();
}
return credential;
}
public void resourceRequest(Context context,int method,String url, Response.Listener listener, Response.ErrorListener errorListener){
RequestQueue queue = Volley.newRequestQueue(context);
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,listener, errorListener) {
@Override
public Map getHeaders() throws AuthFailureError {
Map headers = new HashMap();
String auth = "Bearer "+ credential.getAccessToken();
headers.put("Authorization", auth);
return headers;
}
};
// Add the request to the RequestQueue.
queue.add(stringRequest);
}
public void logout(Context context, String url) {
WebView w= new WebView(context);
w.loadUrl(url);
credential = null;
}
}
Ao clicar no botão de logar, a classe //MainActivity// chama o método //getTokenCredential(...)// passando entre os parâmetros necessários //cliente_id// e //client_secret// da aplicação. Desse modo, é mostrada a tela abaixo, na qual o usuário informa suas credenciais de acesso.
* Tela de //login// da Sinfo
{{:desenvolvimento:especificacoes:2.png?300|}}
Caso o usuário e senha informados sejam válidos, é mostrado ao usuário a tela perguntando se o mesmo autoriza a aplicação a utilizar seus dados, como exibido abaixo.
{{:desenvolvimento:especificacoes:3.png?300|}}
Após o usuário autorizar a aplicação, as credenciais de acesso são retornadas para a mesma e a partir daí ela já pode consumir dados dos recursos disponibilizados pela API da Sinfo.
Desse modo, caso o usuário clique no botão Obter Dados, a aplicação é redirecionada para a //ResultActivity//, exibida abaixo.
* //ResultActivity.java//
//imports omitidos
public class ResultActivity extends AppCompatActivity {
// temporary string to show the parsed response
private String jsonResponse;
// Progress dialog
private ProgressDialog pDialog;
private TextView texto;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
pDialog = new ProgressDialog(this);
pDialog.setMessage("Aguarde ...");
pDialog.setCancelable(false);
reqJson();
texto = (TextView) findViewById(R.id.textoJson);
}
private void reqJson(){
String urlJsonObj = "http://apitestes.info.ufrn.br/usuario-services/services/usuario/info";
OAuthTokenRequest.getInstance().resourceRequest(this, Request.Method.GET, urlJsonObj, new Response.Listener() {
@Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
String nome = jsonObject.getString("nome");
String login = jsonObject.getString("login");
jsonResponse = "";
jsonResponse += "Name: " + nome + "\n\n";
jsonResponse += "Login: " + login + "\n\n";
texto.setText(jsonResponse);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("SAIDA", "Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_SHORT).show();
// hide the progress dialog
}
});
}
}
A //ResultActivity// utiliza o método //resourceRequest(...)// da classe //OAuthTokenRequest// para buscar os dados desejados da API. Após a consulta, a mesma exibe os dados buscados na tela de informações do usuário.
====Android utilizando Client Credentials====
Neste exemplo mostra-se a utilização do fluxo de autorização //client credentials// em uma aplicação Android.
A aplicação possui a funcionalidade básica de buscar uma unidade/setor através do nome, parte do nome(setor ou unidade) ou sigla, e retornar o telefone desses locais. Além dessa funcionalidade básica, o usuário pode adicionar o número a agenda telefônica ou fazer uma ligação.
Os três códigos a seguir mostram como está estruturado a interface do aplicativo:
* //activity_main.xml//
* //content_main.xml//
* //item.xml//
A aplicação possui três estados, o inicial, realizando a pesquisa e resultado final que são mostrados abaixo nas imagens, respectivamente.
{{:desenvolvimento:especificacoes:device-2015-12-18-131006.png?300 |}}{{:desenvolvimento:especificacoes:device-2015-12-18-131056.png?300 |}}{{:desenvolvimento:especificacoes:device-2015-12-18-131117.png?300|}}
A classe que controla todo o aplicativo é a seguinte:
/**
* Created by Vinicius on 09/12/2015.
*/
// imports omitidos
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private List telefones;
private ProgressDialog progressDialog;
private EditText editText;
private ImageButton searchButton;
public MainActivity(){
telefones = new ArrayList();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(false);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerAdapter(telefones, MainActivity.this);
recyclerView.setAdapter(adapter);
editText = (EditText) findViewById(R.id.search_edit_text);
searchButton = (ImageButton) findViewById(R.id.search_button_tel);
searchButton.setOnClickListener(new ImageButton.OnClickListener(){
@Override
public void onClick(View v) {
//Create a new progress dialog
progressDialog = ProgressDialog.show(MainActivity.this, null, "Carregando dados da aplicação...", true);
new Thread(new Runnable() {
@Override
public void run()
{
//Initialize a LoadViewTask object and call the execute() method
String text = OltuJavaClient.getResource(editText.getText().toString());
telefones = new ArrayList();
if(!text.equalsIgnoreCase("")){
try {
JSONArray array = new JSONArray(text);
for(int i = 0; i < array.length(); ++i){
JSONObject jsonList = array.getJSONObject(i);
telefones.add(new TelefoneDTO(jsonList.getString("numero"),
jsonList.getString("descricao"),
jsonList.getString("localizacao"),
jsonList.getString("setor")));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
runOnUiThread(new Runnable() {
@Override
public void run()
{
progressDialog.dismiss();
adapter = new RecyclerAdapter(telefones, MainActivity.this);
recyclerView.setAdapter(adapter);
}
});
}
}).start();
}
});
}
}
Como se pode ver no código acima as requisições a API são realizadas por meio de um cliente OAuth implementado na classe OltuJavaClient, exibida abaixo.
Essa se encarrega de buscar as credenciais da aplicação e os recursos do serviço (getResource(…)). Além disso, para que a mesma funcione é preciso colocar dependências
para as bibliotecas [[http://mvnrepository.com/artifact/org.apache.oltu.oauth2/org.apache.oltu.oauth2.client/0.31|Apache Oltu OAuth 2.0 Client]] e para o [[https://github.com/mcxiaoke/android-volley|Android Volley]].
*//OltuJavaClient//
/**
* Created by Vinicius on 09/12/2015.
*/
//Imports omitidos
public class OltuJavaClient {
public static final String TOKEN_REQUEST_URL = "http://apitestes.info.ufrn.br/authz-server/oauth/token";
//CLIENT_ID E CLIENT_SECRET omitidos
public static final String RESOURCE_URL_TPL = "http://apitestes.info.ufrn.br/telefone-services/services/consulta/telefone/";
public static String getResource(String keyWord){
String resultJson = "";
try {
OAuthClient client = new OAuthClient(new URLConnectionClient());
OAuthClientRequest request =
OAuthClientRequest.tokenLocation(TOKEN_REQUEST_URL)
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.buildQueryMessage();
String token =
client.accessToken(request, OAuthJSONAccessTokenResponse.class)
.getAccessToken();
HttpURLConnection resource_cxn =
(HttpURLConnection)(new URL(RESOURCE_URL_TPL + keyWord).openConnection());
resource_cxn.addRequestProperty("Authorization", "Bearer " + token);
InputStream resource = resource_cxn.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(resource, "UTF-8"));
String line = null;
while ((line = r.readLine()) != null) {
resultJson += line;
}
} catch (Exception exn) {
exn.printStackTrace();
}
return resultJson;
}
}
Ao clicar no ícone de pesquisa o método //getResource()// OltuJavaClient da classe será chamado com o texto contido na caixa de pesquisa.
O resultado dessa requisição é mapeado em na classe TelefoneDTO, que é alocado em uma lista, então utilizando-se de um recycler view os números de telefones são mostrados na tela.
/**
* Created by Vinicius on 09/12/2015.
*/
public class TelefoneDTO {
private String localizacao;
private String setor;
private String descricao;
private String numero;
public TelefoneDTO(String numero, String descricao, String localizacao, String setor){
this.numero = numero;
this.descricao = descricao;
this.localizacao = localizacao;
this.setor = setor;
}
public String getLocalizacao() {
return localizacao;
}
public void setLocalizacao(String localizacao) {
this.localizacao = localizacao;
}
public String getSetor() {
return setor;
}
public void setSetor(String setor) {
this.setor = setor;
}
public String getDescricao() {
return descricao;
}
public void setDescricao(String descricao) {
this.descricao = descricao;
}
public String getNumero() {
return numero;
}
public void setNumero(String numero) {
this.numero = numero;
}
}
====Java utilizando Client Credentials====
Exemplo java aqui.
====Java utilizando Resource Owner Password Credentials====
Exemplo java aqui.
====Java Script====
Exemplo java script aqui.
====Python====
para a utilização com python utilizamos a biblioteca 'requests' para fazer as requisições a api, sendo assim é necessário a instalação da biblioteca a partir do 'pip', com o python instalado na maquina e devidamente configurado, basta rodar o comando:
pip install requests
====Python utilizando Client Credentials====
# -*- coding: utf-8 -*-
import requests
import json
client_id = 'xxxxx' #aqui sua client_id
client_secret = 'xxxxx' #aqui sua client_secret
URL_BASE = 'http://apitestes.info.ufrn.br/'
#injetando parametros na url
url_token = URL_BASE + 'authz-server/oauth/token?client_id={0}&client_secret={1}&grant_type=client_credentials'.format(client_id, client_secret)
#efetuando uma requisicao a api passando a url como parametro
requisicao_token = requests.post(url_token)
#convertendo a resposta json em um objeto python
resposta = json.loads(requisicao_token.content)
#imprimindo resultado da requisição
print 'RESPOSTA: \n'+ str(resposta) #é possivel acessar campos em especifico com 'resposta['campo_que_deseja']'
#salvamos o token em uma variavel pra usar em um exemplo de chamada a api
token = resposta['access_token']
#montamos a url de projetos injetando o token como parametro
URL_Projetos = URL_BASE+ 'projeto-pesquisa-services/services/projetopesquisa?limit=1&access_token={0}'.format(token)
#agora como exemplo fazemos uma requisicao aos projetos de pesquisa com o token obtido
requisicao_projetos = requests.get(URL_Projetos)
#convertemos a resposta para json
projetos = json.loads(requisicao_projetos.content)
#imprimimos o resultado da api de projetos, e possivel acessar campos em especifico com 'resposta['campo_que_deseja']'
print 'PROJETOS: \n'+ str(projetos)
====Python Resource Owner Password Credentials====
import requests
import json
client_secret = 'xxxxx' #aqui sua client_secret
username = 'xxxxx' #aqui seu username
password = 'xxxxx' #aqui seu password
#url da api
URL_BASE = 'http://apitestes.info.ufrn.br/'
#montamos a url de login injetando os parametros definidos no inicio do codigo
url_token = URL_BASE + 'authz-server/oauth/token?client_id={0}&username={1}&password={2}&grant_type=password'.format(client_id, username, password)
# efetuamos uma requisicao a api passando a url_projetos
requisicao_token = requests.post(url_token)
# convertemos o resultado em json para um acesso mais facil aos dados
resposta = json.loads(requisicao_token.content)
# imprimimos o resultado da api, e possivel acessar campos em especifico com 'resposta['campo_que_deseja']'
print resposta
#salvamos o token em uma variavel pra usar em um exemplo de chamada a api
token = resposta['access_token']
#montamos a url de projetos injetando o token como parametro
URL_Projetos = URL_BASE+ 'projeto-pesquisa-services/services/projetopesquisa?limit=1&access_token={0}'.format(token)
#agora como exemplo fazemos uma requisicao aos projetos de pesquisa com o token obtido
requisicao_projetos = requests.get(URL_Projetos)
#convertemos a resposta para json
projetos = json.loads(requisicao_projetos.content)
#imprimimos o resultado da api de projetos, e possivel acessar campos em especifico com 'resposta['campo_que_deseja']'
print projetos
=====Cadastro Aplicação=====
Atualmente, o cadastro da aplicação está sendo realizado depois de requerimento de utilização da API via e-mail enviado ao coordenador do projeto. Logo, para solicitar credenciais de utilização da API, o(a) interessado(a) deve submeter e-mail para api@info.ufrn.br informando quais os dados que deseja utilizar e solicitando credenciais de acesso para a respectiva aplicação.
===== Serviços Disponíveis na API=====
^ Nome ^ Endereço swagger TESTE ^ Endereço swagger PRODUÇÃO ^ Descrição ^
| Bens Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/bens-services/services/swagger.json|bens-services]] | | Permite consultar informações bens da UFRN. |
| Biblioteca Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/biblioteca-services/services/swagger.json|biblioteca-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/biblioteca-services/services/swagger.json|biblioteca-services]] | Permite consultar informações sobre materiais que se encontram no acervo das bibliotecas da universidade. |
| Bolsas Administrativo Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/bolsas-administrativo-services/services/swagger.json|bolsas-administrativo-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/bolsas-administrativo-services/services/swagger.json|bolsas-administrativo-services]] | Permite recuperar informações sobre bolsas no sistema administrativo. |
| Bolsas Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/bolsas-services/services/swagger.json|bolsas-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/bolsas-services/services/swagger.json|bolsas-services]] | Permite recuperar informações sobre bolsas do RU, extensão, pesquisa, monitoria e ações associadas. |
| Comum Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/comum-services/services/swagger.json|comum-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/comum-services/services/swagger.json|comum-services]] | Permite a consulta dos dados comuns aos três sistemas da SINFO (SIGAA, SIGRH e SIPAC). |
| Concursos Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/concursos-services/services/swagger.json|concursos-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/concursos-services/services/swagger.json|concursos-services]] | Permite adquirir informações sobre concursos da universidade. |
| Contratos Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/contratos-services/services/swagger.json|contratos-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/contratos-services/services/swagger.json|contratos-services]] | Permite adquirir informações sobre os contratos de obras licitadas na universidade registrados no SIPAC. |
| Curso Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/curso-services/v0.0.2/swagger.json|curso-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/curso-novo-services/v0.0.1/swagger.json|curso-services]] | Permite consultar informações dos cursos da UFRN. |
| Docente Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/docente-services/services/swagger.json|docente-services]] | | Permite consultar informações dos perfis de docentes da UFRN. |
| Ensino Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/ensino-services/services/swagger.json|ensino-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/ensino-services/services/swagger.json|ensino-services]] | Permite recuperar as informações sobre as turmas registradas no SIGAA, como notícias, tarefas, frequências, notificações, participantes. E permite recuperar informações sobre o aluno, como vínculos, notas, entre outras informações. |
| Fornecedores Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/fornecedores-services/services/swagger.json|fornecedores-services]] | | Permite consultar informações de fornecedores da UFRN. |
| GRU Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/gru-services/services/swagger.json|gru-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/gru-services/services/swagger.json|gru-services]] | Permite a consulta de todas as GRUs (Guia de Recolhimento da União) que foram geradas pelo SIPAC, SIGAA e SIGRH, e também a recuperação de uma GRU especifica, identificada pelo seu número. |
| Materiais Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/materiais-services/services/swagger.json|materiais-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/materiais-services/services/swagger.json|materiais-services]] | Permite adquirir informações sobre materiais adquiridos pela universidade e registrados no SIPAC. |
| Pessoa Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/pessoa-services/services/swagger.json|pessoa-services]] | | Permite retornar informações pessoais dos usuários. |
| Processos Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/processos-services/services/swagger.json|processos-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/processos-services/services/swagger.json|processos-services]] | Permite adquirir informações sobre processos registrados na universidade. |
| Restaurante Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/restaurante-services/services/swagger.json|restaurante-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/restaurante-services/services/swagger.json|restaurante-services]] | Permite recuperar informações sobre o cartão do usuário e sobre os históricos diários de utilização do restaurante universitário. |
| Servidor Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/servidor-services/services/swagger.json|servidor-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/servidor-services/services/swagger.json|servidor-services]] | Permite adquirir informações sobre servidores da universidade. |
| Stricto Sensu Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/stricto-sensu-services/services/swagger.json|stricto-sensu-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/stricto-sensu-services/services/swagger.json|stricto-sensu-services]] | Permite consultar informações (docentes, discentes, projetos) relacionadas a pós do tipo stricto sensu. |
| Telefone Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/telefone-services/services/swagger.json|telefone-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/telefone-services/services/swagger.json|telefone-services]] | Permite consultar informações dos telefones das unidades da UFRN. |
| Unidades Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/unidade-services/services/swagger.json|unidade-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/unidades-services/services/swagger.json|unidades-services]] | Permitir adquirir informações sobre as unidades (centros e departamentos) da universidade. |
| Usuário Services | [[https://apitestes.info.ufrn.br/swagger/index.html?url=https://apitestes.info.ufrn.br/usuario-services/services/swagger.json|usuario-services]] | [[https://api.ufrn.br/swagger/index.html?url=https://api.ufrn.br/usuario-services/services/swagger.json|usuario-services]] | Permite consultar informações sobre o usuários dos sistemas. |