工作上遇到的問題, 雖然有 oracle 證照但是躺在那邊 10 年有了, 也早就忘光光, 工作以來也沒真的用到 oracle, 這次莫名其妙掃被到就玩看看 XD
老實說跟證照考的內容完全沒有任何關係 lol ~
wsl 安裝 docker
因為沒有 systemctl 所以順便記下
1 | # 看目前 ubunt 版本 |
Lab 環境架構
10.1.23.45
=> 我的電腦
172.1.23.45
=> wsl ubuntu 20
(Windows Subsystem for Linux)
docker
上面跑 oracle xe
(nguoianphu/docker-oracle-xe-11g)
wsl ubuntu 20 port 49161 mapping 到 docker port 1521
1 | docker run -dit --name oracle11g -p 49160:22 -p 49161:1521 nguoianphu/docker-oracle-xe-11g |
wsl 又 mapping 到我機器的 port, 所以可以在內網連到
1 | 🌹 netsh interface portproxy show all |
連到 oracle xe
1 | sqlplus testuser1/testuser1@//localhost:49161/xe |
跳到 oracle 的 docker container 裡面
1 | docker exec -it oracle11g /bin/bash |
安裝
安裝參考這篇 不過我沒用 tomcat
官網好像寫說不能用 tomcat9
反正沒我的事, 放生 ~
Oracle Database (Enterprise Edition, Standard Edition or Standard Edition One) release 11.1 or later,
or Oracle Database 11g Release 2 Express Edition. => 以 xe 實測 ok
Java JDK 8 or later. => 他這裡應該是指 oracle database 那台
如果跑 ords 則需要 Java 11
1 | SELECT * FROM v$version; |
先下載回來然後解壓, 會長以下這樣
1 | gg@HQ-XOAH-P05:~$ mkdir ords |
現在執行安裝指令, 執行下去他會跳出問你想要設定的選項, 這裡的帳號要用 sys 不然會陣亡, 可以看官網說明
他還有個快速教學
1 | java -jar ords.war install |
接著會跳其他設定, 這裡就直接預設, 安裝完後他就直接啟動, 有點瞎 XD
1 | Enter a number to update the value or select option A to Accept and Continue |
正常執行 ords 要這樣下
1 | java -jar ords.war serve |
他有提供一個 web 後台, 可以看這篇
比較雷的是以為他中文的綱要是 schema, 實際上則是你開啟 ords mapping 的路徑, 這裡用 qq
的話在 web sql developer
就要先填 qq
同理 OAuth2 Administration
會直接要你敲 Schema
1 | BEGIN |
萬一前面安裝時忘了解鎖這兩個帳號 APEX_PUBLIC_USER
ORDS_PUBLIC_USER
會噴類似的錯誤, 記得使用 sys 登入然後解鎖
ORDS was unable to make a connection to the database. The database user specified by db.username configuration setting is locked. The connection pool named: |default|lo| had the following error(s): ORA-28000: the account is locked
Caused by: java.sql.SQLException: ORA-28000: the account is locked
1 | sqlplus sys@localhost:49161 as sysdba |
以 Oracle 預存程序實作 api
主要參考這篇文章
礙於篇幅因素, 這裡以 rest-v9
為範例示範 CRUD, 其他篇幅請參照他的系列文章及 Oracle 官方文件
請先安裝 postman 進行以下 lab
這裡可以連到以下我 wsl 底下 docker 的 oracle xe 或是自己 pull oracle xe 的 docker image 來裝看看
username
=> system
password
=> oracle
ip
=> 10.1.23.45
port
=> 49161
sid
=> xe
1 | # 讓自己的 wsl 內的 oracle xe 可以讓內網其他人連到 |
建立測試用帳號
登入 system
sqlplus system/oracle@//localhost:49161/xe
1 | CONN / AS SYSDBA |
以 testuser1
登入建立測試資料 sqlplus testuser1/testuser1@//localhost:49161/xe
1 | CREATE TABLE EMP ( |
啟用 ORDS
這個步驟最為重要, 他這裡的 p_url_mapping_pattern
表示路徑 http://localhost:8080/ords/hr/
這個 hr
不能重複
1 | BEGIN |
這裡如果要玩的話可以改用自己喜歡的 test
1 | BEGIN |
撰寫預存程序
建立預存程序 (insert) create_employee
1 | CREATE OR REPLACE PROCEDURE create_employee ( |
建立預存程序 (update) amend_employee
1 | CREATE OR REPLACE PROCEDURE amend_employee ( |
建立預存程序 (delete) remove_employee
1 | CREATE OR REPLACE PROCEDURE remove_employee ( |
撰寫 ORDS API
define_module
=> 先定義模組名稱, 然後定義他的路徑
define_template
=> 定義在哪個路徑, 他這裡用 employees/
因為我們一開始定義在 hr
底下
所以他的最終路徑會長這樣 http://localhost:8080/ords/hr/rest-v9/employees/
這裡還可以在 define_handler
補個註解 p_comments
=> get all employees
這樣他會在 swagger 產出該方法說明
後來發現老外寫說可以用 markdown, 會更詳細些
1 | BEGIN |
以 GET 取得所有 employees
GET 就把他想像成 sql 的查詢即可, 用 get 可以直接用 chrome 點以下網址即可獲得結果, 不須 postman
http://10.1.23.45:8080/ords/hr/rest-v9/employees/
以 GET 取得特定編號員工
http://10.1.23.45:8080/ords/hr/rest-v9/employees/7499
以 POST 新增員工
http://10.1.23.45:8080/ords/hr/rest-v9/employees/
1 | { "empno": 9999, "ename": "HALL", "job": "ANALYST", "mgr": 7782, "hiredate": "2016-01-01", "sal": 1000, "comm": null, "deptno": 10 } |
以 PUT 更新員工
http://10.1.23.45:8080/ords/hr/rest-v9/employees/
1 | { "empno": 9999, "ename": "WOOD", "job": "ANALYST", "mgr": 7782, "hiredate": "2016-01-01", "sal": 1000, "comm": null, "deptno": 20 } |
以 DELETE 刪除員工
http://10.1.23.45:8080/ords/hr/rest-v9/employees/
1 | { "empno": 9999 } |
查目前的 API 路徑
http://10.1.23.45:8080/ords/hr/open-api-catalog/
1 | "items": [{ |
可以點選 links
=> href
內的網址, 點開會有標準的 openapi json
http://10.1.23.45:8080/ords/hr/rest-v1/
1 | { |
貼到 editor.swagger.io 即可看見目前以 PL/SQL 實作之 api 結果
或是使用 redocly 即可在本機產生 swagger 文件
1 | redocly build-docs http://10.1.23.45:8080/ords/hr/open-api-catalog/rest-v9/ --output=index.html |
https 設定
這裡遇到 Invalid SNI 參考老外
1 | java -jar ords.war --config /home/gg/ords config set security.verifySSL false |
他設定檔的位置應該在此 vim ~/ords/global/settings.xml
設定完後就可以用 https 來訪問
https://localhost:8443/ords/hr/open-api-catalog/
settings.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
OAuth
Basic Authentication
請參考這篇
他這裡有串命令官網文件, 跟這教學都沒更新, 只要用下面命令即可正常增加 user
1 | java -jar ords.war config user add emp_user emp_role |
命令如下
1 | BEGIN |
1 | DECLARE |
不用 https 的話就直接下 http://localhost:8080/ords/hr/employees/7788 就直接有結果
client credentials
這裡要先記得開啟 api 保護
1 | DECLARE |
這裡因為是 client credentials 所以只會有 access token, 所以要驗證 token 過期的方法就是看狀態是否 401
可以參考這兩篇
https://www.jmjcloud.com/blog/ords-securing-services-using-oauth2-2-legged
https://www.jmjcloud.com/blog/ords-changing-the-default-oauth2-token-expiry-lifetime
Authorization Code
1 | BEGIN |
這裡的 state
就隨便寫即可, 這裡用 ok
之後會噴這個 401 畫面
輸入帳號 emp_user
及你的密碼即可登入
接著跳這頁要你允許給權限
然後他會跳這頁給你 code
這裡是 rml0SJA1Rx-fe0rCYZaOJg
, 好像有時效性
https://localhost:8443/ords/hr/redirect?code=rml0SJA1Rx-fe0rCYZaOJg&state=ok
用 curl or postman 拿 code 換 token, oauth 最重要口訣就是拿 code 換 token
1 | curl -i -k --user r20KPMlOwi0sYkjkQrH5LQ..:hQPkQgZgVsKEoa4rtW9gXQ.. --data "grant_type=authorization_code&code=vjokEevUwIavYYMRyFLsIg" https://localhost:8443/ords/hr/oauth/token |
最後用 postman 打看看, 也可用 curl
hostname 問題
這裡一樣想對外有可能會噴 Invalid SNI
參考老外
另外還需要先把 ~/ords/global/standalone
底下的這兩個檔案 self-signed.key
self-signed.pem
刪除
接著跑這個命令, 他好像只能指定 唯一
一個, 所以應該是選真實 ip
1 | # for linux |
最後先把 ords
的 web server 重啟
1 | java -jar ords.war serve |
delete
1 | BEGIN |
1 | BEGIN |
ACL 設定
https://oracle-base.com/articles/11g/fine-grained-access-to-network-services-11gr1
ACL 要這樣設定
1 | BEGIN |
這裡要把 UTL_HTTP 開給使用者
並開 acl, 注意 username 要大寫
不然會噴這樣 ORA-44416: Invalid ACL: Unresolved principal ‘testuser1’
1 | GRANT EXECUTE ON UTL_HTTP TO testuser1; |
最後用 TESTUSER1 呼叫個外部的 api 看看, 如果要 https 還要設定錢包, 這裡就懶得弄了
1 | SELECT UTL_HTTP.REQUEST('http://jsonplaceholder.typicode.com/comments?postId=1') DOC |
PL/SQL 用核發的 access token 呼叫 ords 的 api
code 如下, 也是雷了半天
1 | declare |
這裡我測如果用 localhost 的話會噴這樣, 好像只能用 ip 太專業不懂 XD?
1 | <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> |
PL/SQL 拿 ords client_credentials 核發的 access token
拿 token 要用 client_id client_secret 先組 base64 出來, 可以參考這篇
1 | select utl_raw.cast_to_varchar2( |
但是組完後會發現一個問題, 他的字串會有換行符號, 如果這樣丟的話會發生錯誤
“QjVOZ2ZvQlZMUzFuZHRxNGRSSjBFdy4uOmZQa293eGlqUmJUbXZXd001UHI5Qncu
Lg==”
實際上應該要長這樣
“QjVOZ2ZvQlZMUzFuZHRxNGRSSjBFdy4uOmZQa293eGlqUmJUbXZXd001UHI5QncuLg==”
所以可以用以下方式得到一個正確的
1 | select |
最後參考這篇 就可以把 token 印出來囉, 灑花 ~
1 | DECLARE |
PL/SQL 用 authorization code 的 refresh token 取得 access token
這也雷滿久的, 也沒啥文件 QQ
如果是 authorization code
的流程會給你 refresh token
, 如果 client_credentials
則不會給你
這裡一樣先到 http://localhost:8080/ords/hr/oauth/auth?response_type=code&client_id=HUQp7hr7ZAyrnRpOPBbKpw..&state=xxoo
換 code
然後用 curl 拿 code 換 token
1 | curl -i -k --user HUQp7hr7ZAyrnRpOPBbKpw..:DBxFUd6GawcrXWrvokg94g.. --data "grant_type=authorization_code&code=FeCS-XY0HhYNFAQ6u_K0Uw" http://10.1.54.180:8080/ords/hr/oauth/token |
接著要得到 refresh token 他的 curl 是這樣打的, 他也是用 post application/x-www-form-urlencoded
的方式來得到 token
1 | curl --location 'http://localhost:8080/ords/hr/oauth/token' \ |
要記得他跟 client_credentials 發的 client_id , client_secret 是不同低, 可以查這張表看是否已經建立
1 | select * from user_ords_clients; |
以下為 PL/SQL 範例, 應該是不太會用到, 就玩看看 lol
這裡還要注意如果用 &
PL/SQL 會當成要輸入變數值, 所以先用 SET DEFINE OFF
關閉他
1 | SET DEFINE OFF; |
c# call ords
他的 client credentials 是用 username:password 這種模式, 整個詭異 XD
可以看這篇
1 | [ApiController] |
其他
時區
可以參考這裡
如果是 windows 需要設定環境變數, 這篇 有說明各種 java 關於 OPTIONS
的區別
變數 => _JAVA_OPTIONS
值 => -Duser.timezone=Asia/Taipei
linux 則是啟動時直接下 java -Duser.timezone=Asia/Taipei -jar ords.war serve
就搞定惹
或是設定環境變數 JVM_TIMEZONE
1 | vim ~/.bashrc |
windows 安裝
後來發現如果 windows 安裝他好像會自動偵測 tnsnames.ora
然後就會直接出現在選單裡
C:\Users\YOURUSERNAME\Oracle\network\admin\tnsnames.ora
1 | docker11g = |