视频直播鉴权结合业务系统的token或session
Posted bbq烤鸡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了视频直播鉴权结合业务系统的token或session相关的知识,希望对你有一定的参考价值。
视频直播结合业务系统的token或session实现鉴权
前言
视频直播系统和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鉴权,也方便管理。
以上是关于视频直播鉴权结合业务系统的token或session的主要内容,如果未能解决你的问题,请参考以下文章
【SpringCloud-Alibaba系列教程】13.gateway网关结合Sa-token进行登录鉴权
spring-oauth-server实践(1-5)为客户mobile-client开通授权码模式申请access_token,并使用access_token访问需要鉴权的业务