É 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.
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.
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.
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.
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.
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.
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:
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” } ] }
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.
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:
[ { "idTelefone": 0, "localizacao": "string", "setor": "string", "descricao": "string", "numero": "string", "ramais": [ { "numero": "string", "descricao": "string" } ] } ]
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:
{ "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 } ] }
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:
{ "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 } ] }
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:
[ { "idTelefone": 0, "localizacao": "string", "setor": "string", "descricao": "string", "numero": "string", "ramais": [ { "numero": "string", "descricao": "string" } ] } ]
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:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context=".MainActivity"> <android.support.design.widget.AppBarLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> </android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/activity_main" tools:context=".MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/logintxt" android:id="@+id/logarBtn" android:layout_marginBottom="54dp" android:onClick="logar" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_marginLeft="46dp" android:layout_marginStart="46dp" android:layout_marginRight="46dp"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/obter_dados_btn" android:id="@+id/dadosBtn" android:onClick="obterDados" android:layout_alignTop="@+id/logarBtn" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_marginRight="52dp" android:layout_marginEnd="52dp" android:layout_marginLeft="46dp"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sair_btn" android:id="@+id/sairBtn" android:layout_above="@+id/dadosBtn" android:layout_alignRight="@+id/dadosBtn" android:layout_alignEnd="@+id/dadosBtn" android:onClick="sair"/> </RelativeLayout>
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:
//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 Android OAuth Client Library (android-oauth-client) e para o Android Volley
//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<Credential> callback = new OAuthManager.OAuthCallback<Credential>() { @Override public void run(OAuthManager.OAuthFuture<Credential> 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<String> 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<String, String> getHeaders() throws AuthFailureError { Map<String, String> headers = new HashMap<String, String>(); 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.
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.
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.
//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<String>() { @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.
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:
<?xml version="1.0" encoding="UTF-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="br.ufrn.telefoneme.MainActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> </android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="br.ufrn.telefoneme.MainActivity" tools:showIn="@layout/activity_main" android:orientation="horizontal"> <RelativeLayout android:id="@+id/relative_line" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp" android:padding="2dp" android:background="@drawable/border"> <ImageButton android:id="@+id/search_button_tel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/activity_horizontal_margin" android:layout_marginRight="@dimen/activity_horizontal_margin" android:layout_alignParentRight="true" android:layout_marginTop="5dp" android:src="@drawable/ic_magnify" android:background="@android:color/transparent"/> <EditText android:id="@+id/search_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/activity_horizontal_margin" android:layout_toLeftOf="@id/search_button_tel" android:paddingTop="8dp" android:paddingBottom="10dp" android:hint="Unidade, setor ou sigla" android:background="@android:color/white"/> </RelativeLayout> <!-- A RecyclerView with some commonly used attributes --> <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/relative_line"/> </RelativeLayout>
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/activity_vertical_margin" android:layout_marginLeft="@dimen/activity_horizontal_margin" android:phoneNumber="true" android:text="32087795" android:textSize="35sp" android:textColor="@android:color/black"/> <TextView android:id="@+id/descricao" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/activity_horizontal_margin" android:layout_below="@id/number" android:text="Escritório" android:textColor="@android:color/black"/> <TextView android:id="@+id/unidade" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/activity_horizontal_margin" android:layout_below="@id/descricao" android:text="INSTITUTO METROPOLE DIGITAL" android:textColor="@android:color/black"/> <TextView android:id="@+id/setor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/activity_horizontal_margin" android:layout_below="@id/unidade" android:text="UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE" android:textColor="@android:color/black"/> <ImageButton android:id="@+id/call" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="18dp" android:layout_marginRight="@dimen/activity_horizontal_margin" android:src="@drawable/ic_call_white_24dp" android:layout_alignParentRight="true" android:background="@drawable/oval"/> <ImageButton android:id="@+id/add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="18dp" android:layout_marginRight="@dimen/activity_horizontal_margin" android:paddingRight="3dp" android:paddingBottom="1dp" android:src="@drawable/ic_person_add_white_24dp" android:layout_toLeftOf="@id/call" android:background="@drawable/oval"/> <View android:id="@+id/separator" android:layout_width="match_parent" android:layout_height="2dp" android:layout_below="@id/setor" android:layout_marginTop="@dimen/activity_vertical_margin" android:background="@color/black_overlay"/> </RelativeLayout>
A aplicação possui três estados, o inicial, realizando a pesquisa e resultado final que são mostrados abaixo nas imagens, respectivamente.
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<TelefoneDTO> 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<TelefoneDTO>(); 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 Apache Oltu OAuth 2.0 Client e para o Android Volley.
/** * 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; } }
Exemplo java aqui.
Exemplo java aqui.
Exemplo java script aqui.
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
# -*- 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)
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
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.
Nome | Endereço swagger TESTE | Endereço swagger PRODUÇÃO | Descrição |
---|---|---|---|
Bens Services | bens-services | Permite consultar informações bens da UFRN. | |
Biblioteca Services | biblioteca-services | biblioteca-services | Permite consultar informações sobre materiais que se encontram no acervo das bibliotecas da universidade. |
Bolsas Administrativo Services | bolsas-administrativo-services | bolsas-administrativo-services | Permite recuperar informações sobre bolsas no sistema administrativo. |
Bolsas Services | bolsas-services | bolsas-services | Permite recuperar informações sobre bolsas do RU, extensão, pesquisa, monitoria e ações associadas. |
Comum Services | comum-services | comum-services | Permite a consulta dos dados comuns aos três sistemas da SINFO (SIGAA, SIGRH e SIPAC). |
Concursos Services | concursos-services | concursos-services | Permite adquirir informações sobre concursos da universidade. |
Contratos Services | contratos-services | contratos-services | Permite adquirir informações sobre os contratos de obras licitadas na universidade registrados no SIPAC. |
Curso Services | curso-services | curso-services | Permite consultar informações dos cursos da UFRN. |
Docente Services | docente-services | Permite consultar informações dos perfis de docentes da UFRN. | |
Ensino Services | ensino-services | 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 | fornecedores-services | Permite consultar informações de fornecedores da UFRN. | |
GRU Services | gru-services | 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 | materiais-services | materiais-services | Permite adquirir informações sobre materiais adquiridos pela universidade e registrados no SIPAC. |
Pessoa Services | pessoa-services | Permite retornar informações pessoais dos usuários. | |
Processos Services | processos-services | processos-services | Permite adquirir informações sobre processos registrados na universidade. |
Restaurante Services | restaurante-services | 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 | servidor-services | servidor-services | Permite adquirir informações sobre servidores da universidade. |
Stricto Sensu Services | stricto-sensu-services | stricto-sensu-services | Permite consultar informações (docentes, discentes, projetos) relacionadas a pós do tipo stricto sensu. |
Telefone Services | telefone-services | telefone-services | Permite consultar informações dos telefones das unidades da UFRN. |
Unidades Services | unidade-services | unidades-services | Permitir adquirir informações sobre as unidades (centros e departamentos) da universidade. |
Usuário Services | usuario-services | usuario-services | Permite consultar informações sobre o usuários dos sistemas. |