視頻直播結合業務系統的token或session實作鑒權
- 前言
- ■ 需求
- ■ 決議
- 分解步驟
- 開始實作
- ■ Nginx編譯進ngx_http_auth_request_module模塊
- ■ JavaWeb后端提供鑒權介面
- ① authentication認證
- ② authorization授權
- ■ Nginx配置內部鑒權
- ■ postman8.5后的版本可以測驗websocket
- 最后
前言
視頻直播系統和Web后端系統基本是兩套系統,借助Web后端的Shiro框架為視頻直播提供鑒權可以實作非常細粒度的優秀鑒權,
■ 需求
現有兩套系統,業務Web系統、視頻流系統,視頻流播放暫無鑒權,只要知道鏈接人人都可播放,現需要從業務系統獲取內容判斷是否擁有觀看權限,
■ 決議
業務系統后端由Java撰寫,采用Shiro作為鑒權框架,下游使用Nginx作為負載均衡,業務系統里有視頻直播功能,而真正提供視頻流服務的是另一套系統,視頻流系統是怎么實作的我們不需要去關心,只需要知道對外暴露的介面都通過Nginx代理了即可,現在需要做的就是呼叫視頻流服務的介面(即播放等)時,呼叫業務系統的業務邏輯判斷是否有播放權限,才能獲取視頻流,
分解步驟
① JavaWeb后端提供鑒權介面
② 視頻流服務器的下游Nginx攔截播放請求,呼叫JavaWeb后端鑒權才可轉發上游視頻流服務器
③ 前端是否需要做些友好提示
開始實作
■ Nginx編譯進ngx_http_auth_request_module模塊
模塊(1.5.4+)實作了基于一子請求的結果的客戶端的授權,如果子請求回傳2xx回應碼,則允許訪問,如果它回傳401或403,則訪問被拒絕并顯示相應的錯誤代碼,子請求回傳的任何其他回應代碼都被認為是錯誤的,
https://cloud.tencent.com/developer/section/1258993
通俗來說就是編譯了這個模塊后,Nginx在處理請求的時候可以呼叫另一個介面來鑒權,這個介面回傳200回應碼之類才會繼續負載均衡之類,否則會回傳錯誤碼,
編譯時添加引數
--with-http_auth_request_module
Win版Nginx編譯可參考
編譯Windows版Nginx并添加模塊
■ JavaWeb后端提供鑒權介面
在如今的Web專案中,通常認證 (authentication) 和授權 (authorization)失敗后也是回傳http200回應碼,錯誤碼在json中回傳,所以shiro得做些調整,該介面得回傳對應的http回應碼,auth模塊才能識別,
注:authentication和authorization區別?
前者為認證,比如鑒定有沒有token,token是否無效、失效,沒有通過回傳401,
后者為授權,比如token是有效的,但是你沒有權限訪問,回傳403,
① authentication認證
仿這里的認證過濾器
shiro復用session實作前后端分離鑒權
其中過濾器倒二行,回傳碼設定401即可,
/**
* 內部鑒權
* @author bbq
* @version 2021-06-28
*/
@Service
public class InternalAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
/**
這里為自己的一套重寫
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (this.isLoginRequest(request, response)) {
if (this.isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return this.executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
}
return true;
}
} else {
if (log.isTraceEnabled()) {
log.trace("Attempting to access a path which requires authentication. Forwarding to the Authentication url [" + this.getLoginUrl() + "]");
}
ResultDTO retDto = null;
ErrorType et = ErrorType.getOperationType("ERROR_INT_TOKEN_INVALID");
retDto = new ResultDTO(et.getResourceKey(), et.getType(), null);
return responJson(response, retDto);
}
}
// 直接回傳json 并處理跨越
public boolean responJson(ServletResponse response, ResultDTO retDto) throws IOException {
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
httpServletResponse.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept");
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); // 是否允許瀏覽器攜帶用戶身份資訊(cookie)
response = httpServletResponse;
response.getWriter().write(GsonUtils.toJson(retDto));
((HttpServletResponse) response).setStatus(401);
return false;
}
}
② authorization授權
①中過濾器將internalauth介面都攔截了特殊處理,
shiro鑒權可粗可細,三檔次,
粗粒度:第一個介面,只要有登錄(認證通過),即授權成功,
中粒度:第二個介面,在此,我撰寫了一個通用介面供各式各樣的內部鑒權使用,只要用戶具有某個權限識別符號,就可以授權成功,
細粒度:定制介面,可以查詢資料庫等等之類,鑒定更細的業務權限來決定是否授權,
/**
* 內部鑒權Controller
* @author bbq
* @version 2021-6-28
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/internalauth")
public class InternalAuthenticationController extends BaseController {
@ResponseBody
@RequestMapping(value = "base")
public ResultDTO base( HttpServletRequest request, HttpServletResponse response) {
try {
return ResultDTO.buildResult(ResultDTO.SUCCESS_CODE, "成功回傳");
} catch (Exception e) {
return ResultDTO.buildResult(ResultDTO.ERROR_CODE, "引數出錯");
}
}
@ResponseBody
@RequestMapping(value = "advanced/{permitted}")
public ResultDTO advanced(@PathVariable String permitted, HttpServletRequest request, HttpServletResponse response) {
try {
// 即 SecurityUtils.getSubject();
if (UserUtils.getSubject().isPermitted(permitted)) {
return ResultDTO.buildResult(ResultDTO.SUCCESS_CODE, "成功授權");
} else {
response.setStatus(403);
return ResultDTO.buildResult(ResultDTO.SUCCESS_CODE, "沒有權限");
}
} catch (Exception e) {
response.setStatus(403);
return ResultDTO.buildResult(ResultDTO.ERROR_CODE, "引數出錯");
}
}
}
■ Nginx配置內部鑒權
token可通過請求頭傳遞也可以通過url引數傳遞
在這里有個坑,ng呼叫內部介面時$args、 $query_string 等為空,所以難以傳遞url引數,由于時間太久,我也忘了是什么原因,但是 $request_uri是帶有引數的,并且internal中可以獲取,采用正則方式處理一下 $request_uri將?后面引數剝離出來,再傳遞給java端的鑒權介面,
server {
listen 9000;
#listen 9001 ssl http2;
server_name localhost;
ssl相關配置,,,
location / {
auth_request /internalfilter;
error_page 401 = @error401;
error_page 403 = @error403;
proxy_pass http://127.0.0.1:8000/;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /internalfilter {
internal;
proxy_set_header Host $host;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
if ( $request_uri ~ ((\?)([\S\s]*)) ){
set $parameter $1;
}
proxy_pass http://ip:8001/proxy/,,,/internalauth/XXXX$parameter;
}
location @error401 {
return 401 $query_string"沒有登錄";
}
location @error403 {
return 403 "沒有權限訪問";
}
■ postman8.5后的版本可以測驗websocket
專案直播有hls、ws-flv方式,http如常鑒權,ws如例子和http類似,使用8.5以后版本的postman可以測驗,

最后
最后,前端做些友好提示即可,這個方案不僅可以用在視頻流上面,可以為各式各樣的系統提供同一套的shiro鑒權,也方便管理,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291384.html
標籤:其他
上一篇:2021-07-31
