Oracle REST Data Services (ORDS) 安全认证机制

Posted sunansheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle REST Data Services (ORDS) 安全认证机制相关的知识,希望对你有一定的参考价值。

HTTP or HTTPS

By default, the OAuth2 protocol requires all calls to be performed using HTTPS. You can read how to configure Apache Tomcat to enable HTTPS here.

For test purposes, you may want to configure ORDS to allow OAuth over HTTP. Edit the "/u01/ords/conf/ords/defaults.xml", adding the following entry.

<entry key="security.verifySSL">false</entry>

Restart Tomcat for the change to take effect.

$CATALINA_HOME/bin/shutdown.sh
$CATALINA_HOME/bin/startup.sh

Create a Test Database User

We need a new database user for our testing.

CONN / AS SYSDBA
ALTER SESSION SET CONTAINER=pdb1;

DROP USER testuser1 CASCADE;
CREATE USER testuser1 IDENTIFIED BY testuser1
  DEFAULT TABLESPACE users QUOTA UNLIMITED ON users;
  
GRANT CREATE SESSION, CREATE TABLE TO testuser1;

Create and populate a copy of the EMP table.

CONN testuser1/testuser1@pdb1

CREATE TABLE EMP (
  EMPNO NUMBER(4,0), 
  ENAME VARCHAR2(10 BYTE), 
  JOB VARCHAR2(9 BYTE), 
  MGR NUMBER(4,0), 
  HIREDATE DATE, 
  SAL NUMBER(7,2), 
  COMM NUMBER(7,2), 
  DEPTNO NUMBER(2,0), 
  CONSTRAINT PK_EMP PRIMARY KEY (EMPNO)
  );
  
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7369,'SMITH','CLERK',7902,to_date('17-DEC-80','DD-MON-RR'),800,null,20);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7499,'ALLEN','SALESMAN',7698,to_date('20-FEB-81','DD-MON-RR'),1600,300,30);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7521,'WARD','SALESMAN',7698,to_date('22-FEB-81','DD-MON-RR'),1250,500,30);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7566,'JONES','MANAGER',7839,to_date('02-APR-81','DD-MON-RR'),2975,null,20);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7654,'MARTIN','SALESMAN',7698,to_date('28-SEP-81','DD-MON-RR'),1250,1400,30);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7698,'BLAKE','MANAGER',7839,to_date('01-MAY-81','DD-MON-RR'),2850,null,30);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7782,'CLARK','MANAGER',7839,to_date('09-JUN-81','DD-MON-RR'),2450,null,10);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7788,'SCOTT','ANALYST',7566,to_date('19-APR-87','DD-MON-RR'),3000,null,20);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7839,'KING','PRESIDENT',null,to_date('17-NOV-81','DD-MON-RR'),5000,null,10);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7844,'TURNER','SALESMAN',7698,to_date('08-SEP-81','DD-MON-RR'),1500,0,30);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7876,'ADAMS','CLERK',7788,to_date('23-MAY-87','DD-MON-RR'),1100,null,20);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7900,'JAMES','CLERK',7698,to_date('03-DEC-81','DD-MON-RR'),950,null,30);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7902,'FORD','ANALYST',7566,to_date('03-DEC-81','DD-MON-RR'),3000,null,20);
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7934,'MILLER','CLERK',7782,to_date('23-JAN-82','DD-MON-RR'),1300,null,10);
commit;

Enable ORDS and Create a Web Service

Enable REST web services for the test schema. We could use any unique and legal URL mapping pattern for the schema, so it is not necessary to expose the schema name as we have done here.

CONN testuser1/testuser1@pdb1

BEGIN
  ORDS.enable_schema(
    p_enabled             => TRUE,
    p_schema              => 'TESTUSER1',
    p_url_mapping_type    => 'BASE_PATH',
    p_url_mapping_pattern => 'testuser1',
    p_auto_rest_auth      => FALSE
  );
    
  COMMIT;
END;
/

Define a basic web service we can use for the tests.

CONN testuser1/testuser1@pdb1

BEGIN
  ORDS.define_service(
    p_module_name    => 'testmodule1',
    p_base_path      => 'testmodule1/',
    p_pattern        => 'emp/:empno',
    p_method         => 'GET',
    p_source_type    => ORDS.source_type_query,
    p_source         => 'SELECT * FROM emp WHERE empno = :empno',
    p_items_per_page => 0);

  COMMIT;
END;
/

The web service will now be available from the following URLs without authentication.

http://ol7-121.localdomain:8080/ords/pdb1/testuser1/testmodule1/emp/7788
https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788

For the rest of the article I will assume HTTPS has been enabled. If you've enabled HTTP access to OAUTH, then simply change the test URLs accordingly for the tests. The "curl" command below uses the "-k" option to prevent the call from verifying the self-signed certificate used on this server. We can see the expected JSON data is returned.

$ curl -i -k https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 29 Jun 2016 08:35:50 GMT

"items":["empno":7788,"ename":"SCOTT","job":"ANALYST","mgr":7566,"hiredate":"1987-04-18T23:00:00Z","sal":3000,"comm":null,"deptno":20]
$

Now let's start setting up authentication.

ORDS Roles and Privileges

To protect the web service, we need to create a role with an associated privilege, then map the privilege to the web service. Normally, we would expect a role to be a collection of privileges, and of course a single privilege can be part of multiple roles, but in this case we will keep it simple. The following code creates a new role called "emp_role".

CONN testuser1/testuser1@pdb1

BEGIN
  ORDS.create_role(
    p_role_name => 'emp_role'
  );
  
  COMMIT;
END;
/


-- Display the role.
COLUMN name FORMAT A20

SELECT id, name
FROM   user_ords_roles
WHERE  name = 'emp_role';

        ID NAME
---------- --------------------
     10312 emp_role

SQL>

We create a new privilege called "emp_priv", which is associated with the role.

CONN testuser1/testuser1@pdb1

DECLARE
  l_arr OWA.vc_arr;
BEGIN
  l_arr(1) := 'emp_role';
  
  ORDS.define_privilege (
    p_privilege_name => 'emp_priv',
    p_roles          => l_arr,
    p_label          => 'EMP Data',
    p_description    => 'Allow access to the EMP data.'
  );
   
  COMMIT;
END;
/


-- Display the privilege.
COLUMN name FORMAT A20

SELECT id, name
FROM   user_ords_privileges
WHERE  name = 'emp_priv';

        ID NAME
---------- --------------------
     10313 emp_priv

SQL>


-- Display the privilege-role relationship.
COLUMN privilege_name FORMAT A20
COLUMN role_name FORMAT A20

SELECT privilege_id, privilege_name, role_id, role_name
FROM   user_ords_privilege_roles
WHERE  role_name = 'emp_role';

PRIVILEGE_ID PRIVILEGE_NAME          ROLE_ID ROLE_NAME
------------ -------------------- ---------- --------------------
       10313 emp_priv                  10312 emp_role

SQL>

To protect the web service, we associate the privilege directly to a URL pattern.

BEGIN
  ORDS.create_privilege_mapping(
    p_privilege_name => 'emp_priv',
    p_pattern => '/testmodule1/emp/*'
  );     

  COMMIT;
END;
/


-- Display mapping.
COLUMN name FORMAT A20
COLUMN pattern FORMAT A20

SELECT privilege_id, name, pattern
FROM   user_ords_privilege_mappings
WHERE  name = 'emp_priv';

PRIVILEGE_ID NAME                 PATTERN
------------ -------------------- --------------------
       10246 emp_priv             /testmodule1/emp/*

SQL>

Once this mapping is in place, we can no longer access the web service without authentication. At this point we've not defined how we should authenticate, only that authentication is needed to access this resource.

$ curl -i -k https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Content-Type: text/html
Content-Length: 11577
Date: Wed, 29 Jun 2016 08:45:32 GMT
.
. Edited out for brevity.
.
$

First-Party Authentication (Basic Authentication)

If you have to support basic authentication, it is possible by creating users on the ORDS server.

Create a new ORDS user called "emp_user" with access to the "emp_role" role.

$ cd /u01/ords
$ $JAVA_HOME/bin/java -jar ords.war user emp_user emp_role
Enter a password for user emp_user:
Confirm password for user emp_user:
Jun 29, 2016 11:52:42 AM oracle.dbtools.standalone.ModifyUser execute
INFO: Created user: emp_user in file: /u01/ords/conf/ords/credentials
$ 

Access the web service from a browser using the following URL.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788

You are presented with a 401 message, which includes a "sign in" link. Click the link, sign in with the ORDS credentials you just created and you will be directed to web service output.

Alternatively, specify the credentials in a "curl" command.

$ curl -i -k --user emp_user:Password1 https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 02 Jul 2016 06:19:47 GMT

"items":["empno":7788,"ename":"SCOTT","job":"ANALYST","mgr":7566,"hiredate":"1987-04-18T23:00:00Z","sal":3000,"comm":null,"deptno":20]
$

OAuth 2

There are several methods of authenticating to the web service using OAuth 2. Before starting each example, make sure you clean up the OAUTH metadata, as described in the Deleting OAUTH Metadata section. You do not need to delete the web service itself or the ORDS role, privilege and URL mapping. Each authentication example assumes these are already in place.

OAuth 2 revolves around registering clients, which represent a person or an application wanting to access the resource, then associating those clients to roles. Once the client is authenticated, it has access to the protected resources associated with the roles.

 Many of the parameters in calls to the OAUTH package are optional, but cause problems down the line if they are omitted. The OAUTH package calls in the following examples are the simplest I could make them without causing failures. When calling the CREATE_CLIENT procedure, the P_PRIVILEGE_NAMES parameter is mandatory, but it will accept dummy text if you don't want to associate a privilege directly to the client.

OAuth 2 : Client Credentials

The client credentials flow is a two-legged process that seems the most natural to me as I mostly deal with server-server communication, which should have no human interaction. For this flow we use the client credentials to return an access token, which is used to authenticate calls to protected resources. The example steps through the individual calls, but in reality it would be automated by the application.

Remember to clean up the OAUTH metadata, as described in the Deleting OAUTH Metadata section.

Create a client with the grant type of "client_credentials".

CONN testuser1/testuser1@pdb1

BEGIN
  OAUTH.create_client(
    p_name            => 'Emp Client',
    p_grant_type      => 'client_credentials',
    p_owner           => 'My Company Limited',
    p_description     => 'A client for Emp management',
    p_support_email   => 'tim@example.com',
    p_privilege_names => 'emp_priv'
  );

  COMMIT;
END;
/

-- Display client details.
COLUMN name FORMAT A20

SELECT id, name, client_id, client_secret
FROM   user_ords_clients;

        ID NAME                 CLIENT_ID                        CLIENT_SECRET
---------- -------------------- -------------------------------- --------------------------------
     10316 Emp Client           3NvJRo_a0UwGKx7Q-kivtA..         F5WVwyrWxXj3ykmhSONldQ..

SQL>


-- Display client-privilege relationship.
SELECT name, client_name
FROM   user_ords_client_privileges;

NAME                 CLIENT_NAME
-------------------- ------------------------------
emp_priv             Emp Client

SQL>

Associate the client with the role that holds the correct privileges for the resources it needs to access.

BEGIN
  OAUTH.grant_client_role(
    p_client_name => 'Emp Client',
    p_role_name   => 'emp_role'
  );

  COMMIT;
END;
/


-- Display client-role relationship.
COLUMN client_name FORMAT A30
COLUMN role_name FORMAT A20

SELECT client_name, role_name
FROM   user_ords_client_roles;

CLIENT_NAME                    ROLE_NAME
------------------------------ --------------------
Emp Client                     emp_role

SQL>

In order to access the web service, we must first retrieve an access token using the CLIENT_ID and CLIENT_SECRET we queried from the USER_ORDS_CLIENTS view.

CLIENT_ID     : 3NvJRo_a0UwGKx7Q-kivtA..
CLIENT_SECRET : F5WVwyrWxXj3ykmhSONldQ..
OAUTH URL     : https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/token

The example below retrieves the access token. Notice the user format of "CLIENT_ID:CLIENT_SECRET". It is easy to miss the ":" when you look at this for the first time.

$ curl -i -k --user 3NvJRo_a0UwGKx7Q-kivtA..:F5WVwyrWxXj3ykmhSONldQ.. --data "grant_type=client_credentials" https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/token
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 29 Jun 2016 12:07:02 GMT

"access_token":"-zYl-sFyB2iLicAHw2TsRA..","token_type":"bearer","expires_in":3600
$

We can now use the access token to call our web service. Notice the "Authorization: Bearer access-token" entry in the header of the call.

$ curl -i -k -H"Authorization: Bearer -zYl-sFyB2iLicAHw2TsRA.." https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 29 Jun 2016 12:07:31 GMT

"items":["empno":7788,"ename":"SCOTT","job":"ANALYST","mgr":7566,"hiredate":"1987-04-18T23:00:00Z","sal":3000,"comm":null,"deptno":20]
$

We successfully accessed the protected web service.

OAuth 2 : Authorization Code

The authorization code flow is a three-egged process. The user accesses a URL in a browser, which prompts for credentials. Once authenticated, the browser is redirected to a specified page with an authhorization code as one of the parameters in the URL. That authorization code is used in a call to generate an access token, which is used to authenticate calls to protected resources. With the exception of the user confirmation, all the other steps in the flow should be handled by the application. All the steps will be presented separately in the example that follows.

Remember to clean up the OAUTH metadata, as described in the Deleting OAUTH Metadata section.

Create a client using the grant type of "authorization_code". The redirect and support URLs are not real, but we will be able to follow the example through anyway.

CONN testuser1/testuser1@pdb1

BEGIN
  OAUTH.create_client(
    p_name            => 'Emp Client',
    p_grant_type      => 'authorization_code',
    p_owner           => 'My Company Limited',
    p_description     => 'A client for Emp management',
    p_redirect_uri    => 'https://ol7-121.localdomain:8443/ords/pdb1/testuser1/redirect',
    p_support_email   => 'tim@example.com',
    p_support_uri     => 'https://ol7-121.localdomain:8443/ords/pdb1/testuser1/support',
    p_privilege_names => 'emp_priv'
  );

  COMMIT;
END;
/


-- Display client details.
COLUMN name FORMAT A20

SELECT id, name, client_id, client_secret
FROM   user_ords_clients;

        ID NAME                 CLIENT_ID                        CLIENT_SECRET
---------- -------------------- -------------------------------- --------------------------------
     10333 Emp Client           gxqNSyxPbLUJhSj1yBe8qA..         E-_mKJBlOTfTdHc_zISniA..

SQL>

Associate the client with the role that holds the correct privileges for the resources it needs to access.

BEGIN
  OAUTH.grant_client_role(
    p_client_name => 'Emp Client',
    p_role_name   => 'emp_role'
  );

  COMMIT;
END;
/


-- Display client-role relationship.
COLUMN client_name FORMAT A30
COLUMN role_name FORMAT A20

SELECT client_name, role_name
FROM   user_ords_client_roles;

CLIENT_NAME                    ROLE_NAME
------------------------------ --------------------
Emp Client                     emp_role

SQL>

We then attempt to request an authorization code. Notice we are using the CLIENT_ID from the USER_ORDS_CLIENTS view along with a unique string that will represent the state.

CLIENT_ID     : gxqNSyxPbLUJhSj1yBe8qA..
State         : 3668D7A713E93372E0406A38A8C02171
URL           : https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=code&client_id=client_id&state=state

Access the following URL from a browser.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=code&client_id=gxqNSyxPbLUJhSj1yBe8qA..&state=3668D7A713E93372E0406A38A8C02171

You are presented with a 401 message, which includes a "sign in" link. Click the link, sign in with the ORDS credentials you created ealier (emp_user) and you will be directed to an approval page. Click the "Approve" button, which will take you to the redirect page you specified for the client.

The redirect page we specified for the client doesn't really exist, but we can get the authorization code and state from the URL.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/redirect?code=FF-APuIMukuBlrver1XU2A..&state=3668D7A713E93372E0406A38A8C02171

The application should check the state string matches the one used in the initial call. We use the authorization code to retrieve the access token.

CLIENT_ID     : gxqNSyxPbLUJhSj1yBe8qA..
CLIENT_SECRET : E-_mKJBlOTfTdHc_zISniA..
User          : CLIENT_ID:CLIENT_SECRET
Data          : grant_type=authorization_code&code=authorization-code
URL           : https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/token

The following call retrieves the access token.

$ curl -i -k --user gxqNSyxPbLUJhSj1yBe8qA..:E-_mKJBlOTfTdHc_zISniA.. --data "grant_type=authorization_code&code=FF-APuIMukuBlrver1XU2A.." https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/token
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 29 Jun 2016 12:38:52 GMT

"access_token":"cOYb2hFK_SyxOh8o9n6R7A..","token_type":"bearer","expires_in":3600,"refresh_token":"RC33rvSwAfhguraOWlvgfA.."
$

We can now access the protected resource using the access token.

$ curl -i -k -H"Authorization: Bearer cOYb2hFK_SyxOh8o9n6R7A.." https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 29 Jun 2016 12:40:34 GMT

"items":["empno":7788,"ename":"SCOTT","job":"ANALYST","mgr":7566,"hiredate":"1987-04-18T23:00:00Z","sal":3000,"comm":null,"deptno":20]
$

OAuth 2 : Implicit

The implicit flow is a two-legged process that requires user interaction. The user accesses a URL in a browser, which prompts for credentials. Once authenticated, the browser is redirected to a specified page with an access token as one of the parameters in the URL. That access token is used to authenticate calls to protected resources. The example steps through the individual calls, but in reality everything but the user interaction would be automated by the application.

Remember to clean up the OAUTH metadata, as described in the Deleting OAUTH Metadata section.

Create a client using the grant type of "implicit". The redirect and support URLs are not real, but we will be able to follow the example through anyway.

CONN testuser1/testuser1@pdb1

BEGIN
  OAUTH.create_client(
    p_name            => 'Emp Client',
    p_grant_type      => 'implicit',
    p_owner           => 'My Company Limited',
    p_description     => 'A client for Emp management',
    p_redirect_uri    => 'https://ol7-121.localdomain:8443/ords/pdb1/testuser1/redirect',
    p_support_email   => 'tim@example.com',
    p_support_uri     => 'https://ol7-121.localdomain:8443/ords/pdb1/testuser1/support',
    p_privilege_names => 'emp_priv'
  );

  COMMIT;
END;
/


-- Display client details.
COLUMN name FORMAT A20

SELECT id, name, client_id, client_secret
FROM   user_ords_clients;

        ID NAME                 CLIENT_ID                        CLIENT_SECRET
---------- -------------------- -------------------------------- --------------------------------
     10325 Emp Client           0docHbkL8__7Ic58n7GCBA..

SQL>

Associate the client with the role that holds the correct privileges for the resources it needs to access.

BEGIN
  OAUTH.grant_client_role(
    p_client_name => 'Emp Client',
    p_role_name   => 'emp_role'
  );

  COMMIT;
END;
/


-- Display client-role relationship.
COLUMN client_name FORMAT A30
COLUMN role_name FORMAT A20

SELECT client_name, role_name
FROM   user_ords_client_roles;

CLIENT_NAME                    ROLE_NAME
------------------------------ --------------------
Emp Client                     emp_role

SQL>

We then attempt to request an access token. Notice we are using the CLIENT_ID from the USER_ORDS_CLIENTS view along with a unique string that will represent the state.

CLIENT_ID     : 0docHbkL8__7Ic58n7GCBA..
State         : 3668D7A713E93372E0406A38A8C02171
URL           : https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=code&client_id=client_id&state=random-string

Access the following URL from a browser.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=token&client_id=0docHbkL8__7Ic58n7GCBA..&state=3668D7A713E93372E0406A38A8C02171

You are presented with a 401 message, which includes a "sign in" link. Click the link, sign in with the ORDS credentials you created ealier (emp_user) and you will be directed to an approval page. Click the "Approve" button, which will take you to the redirect page you specified for the client.

The redirect page we specified for the client doesn't really exist, but we can get the access token from the URL.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/redirect#token_type=bearer&access_token=5SVR_NVP5N_OnDQt6iSxJg..&expires_in=3600&state=3668D7A713E93372E0406A38A8C02171

The application should check the state string matches the one used in the initial call. We can now access the protected resource using the access token.

$ curl -i -k -H"Authorization: Bearer 5SVR_NVP5N_OnDQt6iSxJg.." https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 29 Jun 2016 12:15:35 GMT

"items":["empno":7788,"ename":"SCOTT","job":"ANALYST","mgr":7566,"hiredate":"1987-04-18T23:00:00Z","sal":3000,"comm":null,"deptno":20]
$

Deleting OAuth Metadata

We remove the OAuth metadata for the client role mapping and the client using the following code. They could be combined as a single block, but I've left them separate so they can be run individually.

BEGIN
  OAUTH.revoke_client_role(
    p_client_name => 'Emp Client',
    p_role_name   => 'emp_role'
  );

  COMMIT;
END;
/

BEGIN
  OAUTH.delete_client(
    p_name => 'Emp Client'
  );

  COMMIT;
END;
/

Deleting ORDS Metadata

The ORDS URL mapping, privilege and roles are deleted using the following code. Once this is removed, the web service will be publicly available again.

BEGIN
  ORDS.delete_privilege_mapping(
    p_privilege_name => 'emp_priv',
    p_pattern => '/testmodule1/emp/*'
  );     

  COMMIT;
END;
/

BEGIN
  ORDS.delete_privilege (
    p_name => 'emp_priv'
  );
   
  COMMIT;
END;
/

BEGIN
  ORDS.delete_role(
    p_role_name => 'emp_role'
  );
  
  COMMIT;
END;
/

以上是关于Oracle REST Data Services (ORDS) 安全认证机制的主要内容,如果未能解决你的问题,请参考以下文章

Rest数据服务查询类-根据sql查询

Rest数据服务查询类-根据id查询

Delphi REST和Cloud Services

Oracle - 在PLSQL中编写REST服务

如何在 Rest Services 中获取 Json 对象?

通过 REST API 发布变量 - Visual Studio Team Services