服务器cookie不再强制关联path
This commit is contained in:
parent
23d793c9c2
commit
42fe7e3dc5
|
|
@ -27,113 +27,138 @@
|
||||||
#include "Util/util.h"
|
#include "Util/util.h"
|
||||||
#include "Util/MD5.h"
|
#include "Util/MD5.h"
|
||||||
#include "Common/config.h"
|
#include "Common/config.h"
|
||||||
#include "CookieManager.h"
|
#include "HttpCookieManager.h"
|
||||||
|
|
||||||
//////////////////////////////CookieData////////////////////////////////////
|
namespace mediakit {
|
||||||
CookieData::CookieData(const CookieManager::Ptr &manager,
|
|
||||||
const string &cookie,
|
//////////////////////////////HttpServerCookie////////////////////////////////////
|
||||||
|
HttpServerCookie::HttpServerCookie(const std::shared_ptr<HttpCookieManager> &manager,
|
||||||
|
const string &cookie_name,
|
||||||
const string &uid,
|
const string &uid,
|
||||||
uint64_t max_elapsed,
|
const string &cookie,
|
||||||
const string &path){
|
uint64_t max_elapsed){
|
||||||
_uid = uid;
|
_uid = uid;
|
||||||
_max_elapsed = max_elapsed;
|
_max_elapsed = max_elapsed;
|
||||||
_cookie_uuid = cookie;
|
_cookie_uuid = cookie;
|
||||||
_path = path;
|
_cookie_name = cookie_name;
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
manager->onAddCookie(path,uid,cookie);
|
manager->onAddCookie(_cookie_name,_uid,_cookie_uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
CookieData::~CookieData() {
|
HttpServerCookie::~HttpServerCookie() {
|
||||||
auto strongManager = _manager.lock();
|
auto strongManager = _manager.lock();
|
||||||
if(strongManager){
|
if(strongManager){
|
||||||
strongManager->onDelCookie(_path,_uid,_cookie_uuid);
|
strongManager->onDelCookie(_cookie_name,_uid,_cookie_uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string CookieData::getCookie(const string &cookie_name) const {
|
|
||||||
return (StrPrinter << cookie_name << "=" << _cookie_uuid << ";expires=" << cookieExpireTime() << ";path=" << _path);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CookieData::isExpired() {
|
const string & HttpServerCookie::getUid() const{
|
||||||
|
return _uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
string HttpServerCookie::getCookie(const string &path) const {
|
||||||
|
return (StrPrinter << _cookie_name << "=" << _cookie_uuid << ";expires=" << cookieExpireTime() << ";path=" << path);
|
||||||
|
}
|
||||||
|
|
||||||
|
const string& HttpServerCookie::getCookie() const {
|
||||||
|
return _cookie_uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string& HttpServerCookie::getCookieName() const{
|
||||||
|
return _cookie_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServerCookie::updateTime() {
|
||||||
|
_ticker.resetTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpServerCookie::isExpired() {
|
||||||
return _ticker.elapsedTime() > _max_elapsed * 1000;
|
return _ticker.elapsedTime() > _max_elapsed * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CookieData::updateTime() {
|
string HttpServerCookie::cookieExpireTime() const{
|
||||||
_ticker.resetTime();
|
|
||||||
}
|
|
||||||
const string & CookieData::getUid() const{
|
|
||||||
return _uid;
|
|
||||||
}
|
|
||||||
string CookieData::cookieExpireTime() const{
|
|
||||||
char buf[64];
|
char buf[64];
|
||||||
time_t tt = time(NULL) + _max_elapsed;
|
time_t tt = time(NULL) + _max_elapsed;
|
||||||
strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
|
strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string& CookieData::getCookie() const {
|
|
||||||
return _cookie_uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string& CookieData::getPath() const{
|
|
||||||
return _path;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////CookieManager////////////////////////////////////
|
//////////////////////////////CookieManager////////////////////////////////////
|
||||||
INSTANCE_IMP(CookieManager);
|
INSTANCE_IMP(HttpCookieManager);
|
||||||
|
|
||||||
CookieData::Ptr CookieManager::addCookie(const string &uidIn, int max_client ,uint64_t max_elapsed, const string &path) {
|
HttpCookieManager::HttpCookieManager() {
|
||||||
|
//定时删除过期的cookie,防止内存膨胀
|
||||||
|
_timer = std::make_shared<Timer>(10,[this](){
|
||||||
|
onManager();
|
||||||
|
return true;
|
||||||
|
}, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpCookieManager::~HttpCookieManager() {
|
||||||
|
_timer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpCookieManager::onManager() {
|
||||||
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
||||||
|
//先遍历所有类型
|
||||||
|
for(auto it_name = _map_cookie.begin() ; it_name != _map_cookie.end() ;){
|
||||||
|
//再遍历该类型下的所有cookie
|
||||||
|
for (auto it_cookie = it_name->second.begin() ; it_cookie != it_name->second.end() ; ){
|
||||||
|
if(it_cookie->second->isExpired()){
|
||||||
|
//cookie过期,移除记录
|
||||||
|
WarnL << it_cookie->second->getUid() << " cookie过期";
|
||||||
|
it_cookie = it_name->second.erase(it_cookie);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++it_cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(it_name->second.empty()){
|
||||||
|
//该类型下没有任何cooki记录,移除之
|
||||||
|
WarnL << "该path下没有任何cooki记录:" << it_name->first;
|
||||||
|
it_name = _map_cookie.erase(it_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++it_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServerCookie::Ptr HttpCookieManager::addCookie(const string &cookie_name,const string &uidIn,uint64_t max_elapsed,int max_client) {
|
||||||
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
||||||
auto cookie = _geneator.obtain();
|
auto cookie = _geneator.obtain();
|
||||||
auto uid = uidIn.empty() ? cookie : uidIn;
|
auto uid = uidIn.empty() ? cookie : uidIn;
|
||||||
auto oldCookie = getOldestCookie(uid, max_client , path);
|
auto oldCookie = getOldestCookie(cookie_name , uid, max_client);
|
||||||
if(!oldCookie.empty()){
|
if(!oldCookie.empty()){
|
||||||
//假如该账号已经登录了,那么删除老的cookie。
|
//假如该账号已经登录了,那么删除老的cookie。
|
||||||
//目的是实现单账号多地登录时挤占登录
|
//目的是实现单账号多地登录时挤占登录
|
||||||
delCookie(oldCookie,path);
|
delCookie(cookie_name,oldCookie);
|
||||||
}
|
}
|
||||||
CookieData::Ptr data(new CookieData(shared_from_this(),cookie,uid,max_elapsed,path));
|
HttpServerCookie::Ptr data(new HttpServerCookie(shared_from_this(),cookie_name,uid,cookie,max_elapsed));
|
||||||
//保存该账号下的新cookie
|
//保存该账号下的新cookie
|
||||||
_map_cookie[path][cookie] = data;
|
_map_cookie[cookie_name][cookie] = data;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CookieManager::delCookie(const CookieData::Ptr &cookie) {
|
HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,const string &cookie) {
|
||||||
if(!cookie){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return delCookie(cookie->getPath(),cookie->getCookie());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CookieManager::delCookie(const string &path , const string &cookie) {
|
|
||||||
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
||||||
auto it = _map_cookie.find(path);
|
auto it_name = _map_cookie.find(cookie_name);
|
||||||
if(it == _map_cookie.end()){
|
if(it_name == _map_cookie.end()){
|
||||||
return false;
|
//不存在该类型的cookie
|
||||||
}
|
|
||||||
return it->second.erase(cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
CookieData::Ptr CookieManager::getCookie(const string &cookie, const string &path) {
|
|
||||||
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
|
||||||
auto it_path = _map_cookie.find(path);
|
|
||||||
if(it_path == _map_cookie.end()){
|
|
||||||
//该path下没有任何cookie
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto it_cookie = it_path->second.find(cookie);
|
auto it_cookie = it_name->second.find(cookie);
|
||||||
if(it_cookie == it_path->second.end()){
|
if(it_cookie == it_name->second.end()){
|
||||||
//该path下没有对应的cookie
|
//该类型下没有对应的cookie
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if(it_cookie->second->isExpired()){
|
if(it_cookie->second->isExpired()){
|
||||||
//cookie过期
|
//cookie过期
|
||||||
it_path->second.erase(it_cookie);
|
it_name->second.erase(it_cookie);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return it_cookie->second;
|
return it_cookie->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
CookieData::Ptr CookieManager::getCookie(const StrCaseMap &http_header, const string &cookie_name, const string &path) {
|
HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,const StrCaseMap &http_header) {
|
||||||
auto it = http_header.find("Cookie");
|
auto it = http_header.find("Cookie");
|
||||||
if (it == http_header.end()) {
|
if (it == http_header.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -145,64 +170,43 @@ CookieData::Ptr CookieManager::getCookie(const StrCaseMap &http_header, const st
|
||||||
if(cookie.empty()){
|
if(cookie.empty()){
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return CookieManager::Instance().getCookie(cookie, path);
|
return HttpCookieManager::Instance().getCookie(cookie_name , cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
CookieManager::CookieManager() {
|
bool HttpCookieManager::delCookie(const HttpServerCookie::Ptr &cookie) {
|
||||||
//定时删除过期的cookie,防止内存膨胀
|
if(!cookie){
|
||||||
_timer = std::make_shared<Timer>(10,[this](){
|
return false;
|
||||||
onManager();
|
}
|
||||||
return true;
|
return delCookie(cookie->getCookieName(),cookie->getCookie());
|
||||||
}, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CookieManager::~CookieManager() {
|
bool HttpCookieManager::delCookie(const string &cookie_name,const string &cookie) {
|
||||||
_timer.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CookieManager::onManager() {
|
|
||||||
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
||||||
//先遍历所有path
|
auto it_name = _map_cookie.find(cookie_name);
|
||||||
for(auto it_path = _map_cookie.begin() ; it_path != _map_cookie.end() ;){
|
if(it_name == _map_cookie.end()){
|
||||||
//再遍历该path下的所有cookie
|
return false;
|
||||||
for (auto it_cookie = it_path->second.begin() ; it_cookie != it_path->second.end() ; ){
|
|
||||||
if(it_cookie->second->isExpired()){
|
|
||||||
//cookie过期,移除记录
|
|
||||||
WarnL << it_cookie->second->getUid() << " cookie过期";
|
|
||||||
it_cookie = it_path->second.erase(it_cookie);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
++it_cookie;
|
return it_name->second.erase(cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(it_path->second.empty()){
|
void HttpCookieManager::onAddCookie(const string &cookie_name,const string &uid,const string &cookie){
|
||||||
//该path下没有任何cooki记录,移除之
|
|
||||||
WarnL << "该path下没有任何cooki记录:" << it_path->first;
|
|
||||||
it_path = _map_cookie.erase(it_path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++it_path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CookieManager::onAddCookie(const string &path,const string &uid,const string &cookie){
|
|
||||||
//添加新的cookie,我们记录下这个uid下有哪些cookie,目的是实现单账号多地登录时挤占登录
|
//添加新的cookie,我们记录下这个uid下有哪些cookie,目的是实现单账号多地登录时挤占登录
|
||||||
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
||||||
//相同用户下可以存在多个cookie(意味多地登录),这些cookie根据登录时间的早晚依次排序
|
//相同用户下可以存在多个cookie(意味多地登录),这些cookie根据登录时间的早晚依次排序
|
||||||
_map_uid_to_cookie[path][uid][getCurrentMillisecond()] = cookie;
|
_map_uid_to_cookie[cookie_name][uid][getCurrentMillisecond()] = cookie;
|
||||||
}
|
}
|
||||||
void CookieManager::onDelCookie(const string &path,const string &uid,const string &cookie){
|
void HttpCookieManager::onDelCookie(const string &cookie_name,const string &uid,const string &cookie){
|
||||||
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
||||||
//回收随机字符串
|
//回收随机字符串
|
||||||
_geneator.release(cookie);
|
_geneator.release(cookie);
|
||||||
|
|
||||||
auto it_path = _map_uid_to_cookie.find(path);
|
auto it_name = _map_uid_to_cookie.find(cookie_name);
|
||||||
if(it_path == _map_uid_to_cookie.end()){
|
if(it_name == _map_uid_to_cookie.end()){
|
||||||
//该path下未有任意用户登录
|
//该类型下未有任意用户登录
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto it_uid = it_path->second.find(uid);
|
auto it_uid = it_name->second.find(uid);
|
||||||
if(it_uid == it_path->second.end()){
|
if(it_uid == it_name->second.end()){
|
||||||
//该用户尚未登录
|
//该用户尚未登录
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -221,27 +225,27 @@ void CookieManager::onDelCookie(const string &path,const string &uid,const strin
|
||||||
}
|
}
|
||||||
|
|
||||||
//该用户名下没有任何设备在线,移除之
|
//该用户名下没有任何设备在线,移除之
|
||||||
it_path->second.erase(it_uid);
|
it_name->second.erase(it_uid);
|
||||||
|
|
||||||
if(it_path->second.size() != 0) {
|
if(it_name->second.size() != 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//该path下未有任何用户在线,移除之
|
//该类型下未有任何用户在线,移除之
|
||||||
_map_uid_to_cookie.erase(it_path);
|
_map_uid_to_cookie.erase(it_name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string CookieManager::getOldestCookie(const string &uid, int max_client,const string &path){
|
string HttpCookieManager::getOldestCookie(const string &cookie_name,const string &uid, int max_client){
|
||||||
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
||||||
auto it_path = _map_uid_to_cookie.find(path);
|
auto it_name = _map_uid_to_cookie.find(cookie_name);
|
||||||
if(it_path == _map_uid_to_cookie.end()){
|
if(it_name == _map_uid_to_cookie.end()){
|
||||||
//该路径下未有任意cookie
|
//不存在该类型的cookie
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
auto it_uid = it_path->second.find(uid);
|
auto it_uid = it_name->second.find(uid);
|
||||||
if(it_uid == it_path->second.end()){
|
if(it_uid == it_name->second.end()){
|
||||||
//该用户从未登录过
|
//该用户从未登录过
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -253,8 +257,8 @@ string CookieManager::getOldestCookie(const string &uid, int max_client,const st
|
||||||
return it_uid->second.begin()->second;
|
return it_uid->second.begin()->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////CookieGeneator////////////////////////////////////
|
/////////////////////////////////RandStrGeneator////////////////////////////////////
|
||||||
string CookieGeneator::obtain(){
|
string RandStrGeneator::obtain(){
|
||||||
//获取唯一的防膨胀的随机字符串
|
//获取唯一的防膨胀的随机字符串
|
||||||
while (true){
|
while (true){
|
||||||
auto str = obtain_l();
|
auto str = obtain_l();
|
||||||
|
|
@ -265,15 +269,17 @@ string CookieGeneator::obtain(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void CookieGeneator::release(const string &str){
|
void RandStrGeneator::release(const string &str){
|
||||||
//从防膨胀库中移除
|
//从防膨胀库中移除
|
||||||
_obtained.erase(str);
|
_obtained.erase(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
string CookieGeneator::obtain_l(){
|
string RandStrGeneator::obtain_l(){
|
||||||
//12个伪随机字节 + 4个递增的整形字节,然后md5即为随机字符串
|
//12个伪随机字节 + 4个递增的整形字节,然后md5即为随机字符串
|
||||||
auto str = makeRandStr(12,false);
|
auto str = makeRandStr(12,false);
|
||||||
str.append((char *)&_index, sizeof(_index));
|
str.append((char *)&_index, sizeof(_index));
|
||||||
++_index;
|
++_index;
|
||||||
return MD5(str).hexdigest();
|
return MD5(str).hexdigest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}//namespace mediakit
|
||||||
|
|
@ -40,25 +40,31 @@ using namespace mediakit;
|
||||||
|
|
||||||
#define COOKIE_DEFAULT_LIFE (7 * 24 * 60 * 60)
|
#define COOKIE_DEFAULT_LIFE (7 * 24 * 60 * 60)
|
||||||
|
|
||||||
class CookieManager;
|
namespace mediakit {
|
||||||
|
|
||||||
|
class HttpCookieManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cookie对象,用于保存cookie的一些相关属性
|
* cookie对象,用于保存cookie的一些相关属性
|
||||||
*/
|
*/
|
||||||
class CookieData : public mINI , public noncopyable{
|
class HttpServerCookie : public mINI , public noncopyable{
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<CookieData> Ptr;
|
typedef std::shared_ptr<HttpServerCookie> Ptr;
|
||||||
/**
|
/**
|
||||||
* 构建cookie
|
* 构建cookie
|
||||||
* @param manager cookie管理者对象
|
* @param manager cookie管理者对象
|
||||||
* @param cookie cookie随机字符串
|
* @param cookie_name cookie名,例如MY_SESSION
|
||||||
* @param uid 用户唯一id
|
* @param uid 用户唯一id
|
||||||
|
* @param cookie cookie随机字符串
|
||||||
* @param max_elapsed 最大过期时间,单位秒
|
* @param max_elapsed 最大过期时间,单位秒
|
||||||
* @param path http路径,譬如/index/files/
|
|
||||||
*/
|
*/
|
||||||
CookieData(const std::shared_ptr<CookieManager> &manager,const string &cookie,
|
|
||||||
const string &uid,uint64_t max_elapsed,const string &path);
|
HttpServerCookie(const std::shared_ptr<HttpCookieManager> &manager,
|
||||||
~CookieData() ;
|
const string &cookie_name,
|
||||||
|
const string &uid,
|
||||||
|
const string &cookie,
|
||||||
|
uint64_t max_elapsed);
|
||||||
|
~HttpServerCookie() ;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取uid
|
* 获取uid
|
||||||
|
|
@ -69,9 +75,10 @@ public:
|
||||||
/**
|
/**
|
||||||
* 获取http中Set-Cookie字段的值
|
* 获取http中Set-Cookie字段的值
|
||||||
* @param cookie_name 该cookie的名称,譬如 MY_SESSION
|
* @param cookie_name 该cookie的名称,譬如 MY_SESSION
|
||||||
|
* @param path http访问路径
|
||||||
* @return 例如 MY_SESSION=XXXXXX;expires=Wed, Jun 12 2019 06:30:48 GMT;path=/index/files/
|
* @return 例如 MY_SESSION=XXXXXX;expires=Wed, Jun 12 2019 06:30:48 GMT;path=/index/files/
|
||||||
*/
|
*/
|
||||||
string getCookie(const string &cookie_name) const;
|
string getCookie(const string &path) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取cookie随机字符串
|
* 获取cookie随机字符串
|
||||||
|
|
@ -80,10 +87,10 @@ public:
|
||||||
const string& getCookie() const;
|
const string& getCookie() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取该cookie对应的path
|
* 获取该cookie名
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
const string& getPath() const;
|
const string& getCookieName() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新该cookie的过期时间,可以让此cookie不失效
|
* 更新该cookie的过期时间,可以让此cookie不失效
|
||||||
|
|
@ -99,20 +106,20 @@ private:
|
||||||
string cookieExpireTime() const ;
|
string cookieExpireTime() const ;
|
||||||
private:
|
private:
|
||||||
string _uid;
|
string _uid;
|
||||||
string _path;
|
string _cookie_name;
|
||||||
string _cookie_uuid;
|
string _cookie_uuid;
|
||||||
uint64_t _max_elapsed;
|
uint64_t _max_elapsed;
|
||||||
Ticker _ticker;
|
Ticker _ticker;
|
||||||
std::weak_ptr<CookieManager> _manager;
|
std::weak_ptr<HttpCookieManager> _manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cookie随机字符串生成器
|
* cookie随机字符串生成器
|
||||||
*/
|
*/
|
||||||
class CookieGeneator{
|
class RandStrGeneator{
|
||||||
public:
|
public:
|
||||||
CookieGeneator() = default;
|
RandStrGeneator() = default;
|
||||||
~CookieGeneator() = default;
|
~RandStrGeneator() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取不碰撞的随机字符串
|
* 获取不碰撞的随机字符串
|
||||||
|
|
@ -138,95 +145,94 @@ private:
|
||||||
* cookie管理器,用于管理cookie的生成以及过期管理,同时实现了同账号异地挤占登录功能
|
* cookie管理器,用于管理cookie的生成以及过期管理,同时实现了同账号异地挤占登录功能
|
||||||
* 该对象实现了同账号最多登录若干个设备
|
* 该对象实现了同账号最多登录若干个设备
|
||||||
*/
|
*/
|
||||||
class CookieManager : public std::enable_shared_from_this<CookieManager> {
|
class HttpCookieManager : public std::enable_shared_from_this<HttpCookieManager> {
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<CookieManager> Ptr;
|
typedef std::shared_ptr<HttpCookieManager> Ptr;
|
||||||
friend class CookieData;
|
friend class HttpServerCookie;
|
||||||
~CookieManager();
|
~HttpCookieManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取单例
|
* 获取单例
|
||||||
*/
|
*/
|
||||||
static CookieManager &Instance();
|
static HttpCookieManager &Instance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加cookie
|
* 添加cookie
|
||||||
|
* @param cookie_name cookie名,例如MY_SESSION
|
||||||
* @param uid 用户id,如果为空则为匿名登录
|
* @param uid 用户id,如果为空则为匿名登录
|
||||||
* @param max_client 该账号最多登录多少个设备
|
* @param max_client 该账号最多登录多少个设备
|
||||||
* @param max_elapsed 该cookie过期时间,单位秒
|
* @param max_elapsed 该cookie过期时间,单位秒
|
||||||
* @param path 该cookie对应的http路径
|
|
||||||
* @return cookie对象
|
* @return cookie对象
|
||||||
*/
|
*/
|
||||||
CookieData::Ptr addCookie(const string &uid, int max_client , uint64_t max_elapsed = COOKIE_DEFAULT_LIFE,const string &path = "/" );
|
HttpServerCookie::Ptr addCookie(const string &cookie_name,const string &uid, uint64_t max_elapsed = COOKIE_DEFAULT_LIFE,int max_client = 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据cookie随机字符串查找cookie对象
|
* 根据cookie随机字符串查找cookie对象
|
||||||
|
* @param cookie_name cookie名,例如MY_SESSION
|
||||||
* @param cookie cookie随机字符串
|
* @param cookie cookie随机字符串
|
||||||
* @param path 该cookie对应的http路径
|
|
||||||
* @return cookie对象,可以为nullptr
|
* @return cookie对象,可以为nullptr
|
||||||
*/
|
*/
|
||||||
CookieData::Ptr getCookie(const string &cookie,const string &path = "/");
|
HttpServerCookie::Ptr getCookie(const string &cookie_name,const string &cookie);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从http头中获取cookie对象
|
* 从http头中获取cookie对象
|
||||||
|
* @param cookie_name cookie名,例如MY_SESSION
|
||||||
* @param http_header http头
|
* @param http_header http头
|
||||||
* @param cookie_name cookie名
|
|
||||||
* @param path http路径
|
|
||||||
* @return cookie对象
|
* @return cookie对象
|
||||||
*/
|
*/
|
||||||
CookieData::Ptr getCookie(const StrCaseMap &http_header,const string &cookie_name , const string &path = "/");
|
HttpServerCookie::Ptr getCookie(const string &cookie_name,const StrCaseMap &http_header);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除cookie,用户登出时使用
|
* 删除cookie,用户登出时使用
|
||||||
* @param cookie cookie对象,可以为nullptr
|
* @param cookie cookie对象,可以为nullptr
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool delCookie(const CookieData::Ptr &cookie);
|
bool delCookie(const HttpServerCookie::Ptr &cookie);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某用户名下最先登录时的cookie,目的是实现某用户下最多登录若干个设备
|
* 获取某用户名下最先登录时的cookie,目的是实现某用户下最多登录若干个设备
|
||||||
* @param path http路径
|
* @param cookie_name cookie名,例如MY_SESSION
|
||||||
* @param uid 用户id
|
* @param uid 用户id
|
||||||
* @param max_client 最多登录的设备个数
|
* @param max_client 最多登录的设备个数
|
||||||
* @return 最早的cookie随机字符串
|
* @return 最早的cookie随机字符串
|
||||||
*/
|
*/
|
||||||
string getOldestCookie( const string &uid, int max_client ,const string &path = "/");
|
string getOldestCookie(const string &cookie_name,const string &uid, int max_client = 1);
|
||||||
private:
|
private:
|
||||||
CookieManager();
|
HttpCookieManager();
|
||||||
void onManager();
|
void onManager();
|
||||||
/**
|
/**
|
||||||
* 构造cookie对象时触发,目的是记录某账号下多个cookie
|
* 构造cookie对象时触发,目的是记录某账号下多个cookie
|
||||||
* @param path http路径
|
* @param cookie_name cookie名,例如MY_SESSION
|
||||||
* @param uid 用户id
|
* @param uid 用户id
|
||||||
* @param cookie cookie随机字符串
|
* @param cookie cookie随机字符串
|
||||||
*/
|
*/
|
||||||
void onAddCookie(const string &path,const string &uid,const string &cookie);
|
void onAddCookie(const string &cookie_name,const string &uid,const string &cookie);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 析构cookie对象时触发
|
* 析构cookie对象时触发
|
||||||
* @param path http路径
|
* @param cookie_name cookie名,例如MY_SESSION
|
||||||
* @param uid 用户id
|
* @param uid 用户id
|
||||||
* @param cookie cookie随机字符串
|
* @param cookie cookie随机字符串
|
||||||
*/
|
*/
|
||||||
void onDelCookie(const string &path,const string &uid,const string &cookie);
|
void onDelCookie(const string &cookie_name,const string &uid,const string &cookie);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除cookie
|
* 删除cookie
|
||||||
* @param path http路径
|
* @param cookie_name cookie名,例如MY_SESSION
|
||||||
* @param cookie cookie随机字符串
|
* @param cookie cookie随机字符串
|
||||||
* @return 成功true
|
* @return 成功true
|
||||||
*/
|
*/
|
||||||
bool delCookie(const string &path,const string &cookie);
|
bool delCookie(const string &cookie_name,const string &cookie);
|
||||||
private:
|
private:
|
||||||
unordered_map<string/*path*/,unordered_map<string/*cookie*/,CookieData::Ptr/*cookie_data*/> >_map_cookie;
|
unordered_map<string/*cookie_name*/,unordered_map<string/*cookie*/,HttpServerCookie::Ptr/*cookie_data*/> >_map_cookie;
|
||||||
unordered_map<string/*path*/,unordered_map<string/*uid*/,map<uint64_t/*cookie time stamp*/,string/*cookie*/> > >_map_uid_to_cookie;
|
unordered_map<string/*cookie_name*/,unordered_map<string/*uid*/,map<uint64_t/*cookie time stamp*/,string/*cookie*/> > >_map_uid_to_cookie;
|
||||||
recursive_mutex _mtx_cookie;
|
recursive_mutex _mtx_cookie;
|
||||||
Timer::Ptr _timer;
|
Timer::Ptr _timer;
|
||||||
CookieGeneator _geneator;
|
RandStrGeneator _geneator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}//namespace mediakit
|
||||||
|
|
||||||
|
|
||||||
#endif //SRC_HTTP_COOKIEMANAGER_H
|
#endif //SRC_HTTP_COOKIEMANAGER_H
|
||||||
|
|
@ -51,7 +51,6 @@ namespace mediakit {
|
||||||
static int kSockFlags = SOCKET_DEFAULE_FLAGS | FLAG_MORE;
|
static int kSockFlags = SOCKET_DEFAULE_FLAGS | FLAG_MORE;
|
||||||
static const string kCookieName = "ZL_COOKIE";
|
static const string kCookieName = "ZL_COOKIE";
|
||||||
static const string kAccessPathKey = "kAccessPathKey";
|
static const string kAccessPathKey = "kAccessPathKey";
|
||||||
static int kMaxClientPerUid = 1;
|
|
||||||
static const string kAccessDirUnauthorized = "你没有权限访问该目录";
|
static const string kAccessDirUnauthorized = "你没有权限访问该目录";
|
||||||
static const string kAccessFileUnauthorized = "你没有权限访问该文件";
|
static const string kAccessFileUnauthorized = "你没有权限访问该文件";
|
||||||
|
|
||||||
|
|
@ -331,7 +330,7 @@ inline string HttpSession::getClientUid(){
|
||||||
NoticeCenter::Instance().emitEventNoCopy(Broadcast::kBroadcastTrackHttpClient,_parser,uid,*this);
|
NoticeCenter::Instance().emitEventNoCopy(Broadcast::kBroadcastTrackHttpClient,_parser,uid,*this);
|
||||||
return uid;
|
return uid;
|
||||||
}
|
}
|
||||||
inline void HttpSession::canAccessPath(const string &path_in,bool is_dir,const function<void(bool canAccess,const CookieData::Ptr &cookie)> &callback_in){
|
inline void HttpSession::canAccessPath(const string &path_in,bool is_dir,const function<void(bool canAccess,const HttpServerCookie::Ptr &cookie)> &callback_in){
|
||||||
if(NoticeCenter::Instance().listenerSize(Broadcast::kBroadcastHttpAccess) == 0){
|
if(NoticeCenter::Instance().listenerSize(Broadcast::kBroadcastHttpAccess) == 0){
|
||||||
//该事件无人监听,那么就不做cookie查找这样费时的操作
|
//该事件无人监听,那么就不做cookie查找这样费时的操作
|
||||||
callback_in(true, nullptr);
|
callback_in(true, nullptr);
|
||||||
|
|
@ -340,7 +339,7 @@ inline void HttpSession::canAccessPath(const string &path_in,bool is_dir,const f
|
||||||
auto path = path_in;
|
auto path = path_in;
|
||||||
replace(const_cast<string &>(path),"//","/");
|
replace(const_cast<string &>(path),"//","/");
|
||||||
|
|
||||||
auto callback = [callback_in,this](bool canAccess,const CookieData::Ptr &cookie){
|
auto callback = [callback_in,this](bool canAccess,const HttpServerCookie::Ptr &cookie){
|
||||||
try {
|
try {
|
||||||
callback_in(canAccess,cookie);
|
callback_in(canAccess,cookie);
|
||||||
}catch (SockException &ex){
|
}catch (SockException &ex){
|
||||||
|
|
@ -353,7 +352,7 @@ inline void HttpSession::canAccessPath(const string &path_in,bool is_dir,const f
|
||||||
};
|
};
|
||||||
|
|
||||||
//根据http头中的cookie字段获取cookie
|
//根据http头中的cookie字段获取cookie
|
||||||
auto cookie = CookieManager::Instance().getCookie(_parser.getValues(), kCookieName);
|
auto cookie = HttpCookieManager::Instance().getCookie(kCookieName,_parser.getValues());
|
||||||
if (cookie) {
|
if (cookie) {
|
||||||
//判断该用户是否有权限访问该目录,并且不再设置客户端cookie
|
//判断该用户是否有权限访问该目录,并且不再设置客户端cookie
|
||||||
callback(!(*cookie)[kAccessPathKey].empty() && path.find((*cookie)[kAccessPathKey]) == 0, nullptr);
|
callback(!(*cookie)[kAccessPathKey].empty() && path.find((*cookie)[kAccessPathKey]) == 0, nullptr);
|
||||||
|
|
@ -362,10 +361,10 @@ inline void HttpSession::canAccessPath(const string &path_in,bool is_dir,const f
|
||||||
|
|
||||||
//根据该用户的用户名获取cookie
|
//根据该用户的用户名获取cookie
|
||||||
string uid = getClientUid();
|
string uid = getClientUid();
|
||||||
auto cookie_str = CookieManager::Instance().getOldestCookie(uid, kMaxClientPerUid);
|
auto cookie_str = HttpCookieManager::Instance().getOldestCookie(kCookieName,uid);
|
||||||
if(!cookie_str.empty()){
|
if(!cookie_str.empty()){
|
||||||
//该用户已经登录过了,但是它(http客户端)貌似不支持cookie,所以我们只能通过它的用户名获取cookie
|
//该用户已经登录过了,但是它(http客户端)貌似不支持cookie,所以我们只能通过它的用户名获取cookie
|
||||||
cookie = CookieManager::Instance().getCookie(cookie_str);
|
cookie = HttpCookieManager::Instance().getCookie(kCookieName,cookie_str);
|
||||||
if (cookie) {
|
if (cookie) {
|
||||||
//判断该用户是否有权限访问该目录,并且不再设置客户端cookie
|
//判断该用户是否有权限访问该目录,并且不再设置客户端cookie
|
||||||
callback(!(*cookie)[kAccessPathKey].empty() && path.find((*cookie)[kAccessPathKey]) == 0, nullptr);
|
callback(!(*cookie)[kAccessPathKey].empty() && path.find((*cookie)[kAccessPathKey]) == 0, nullptr);
|
||||||
|
|
@ -390,12 +389,13 @@ inline void HttpSession::canAccessPath(const string &path_in,bool is_dir,const f
|
||||||
}
|
}
|
||||||
if(cookieLifeSecond){
|
if(cookieLifeSecond){
|
||||||
//我们给用户生成追踪cookie
|
//我们给用户生成追踪cookie
|
||||||
auto cookie = CookieManager::Instance().addCookie(uid, kMaxClientPerUid, cookieLifeSecond);
|
auto cookie = HttpCookieManager::Instance().addCookie(kCookieName,uid,cookieLifeSecond);
|
||||||
//记录用户能访问的路径
|
//记录用户能访问的路径
|
||||||
(*cookie)[kAccessPathKey] = accessPath;
|
(*cookie)[kAccessPathKey] = accessPath;
|
||||||
//判断该用户是否有权限访问该目录,并且设置客户端cookie
|
//判断该用户是否有权限访问该目录,并且设置客户端cookie
|
||||||
callback(!accessPath.empty() && path.find(accessPath) == 0, cookie);
|
callback(!accessPath.empty() && path.find(accessPath) == 0, cookie);
|
||||||
}else{
|
}else{
|
||||||
|
//仅限本次访问文件
|
||||||
callback(!accessPath.empty() && path.find(accessPath) == 0, nullptr);
|
callback(!accessPath.empty() && path.find(accessPath) == 0, nullptr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -462,13 +462,13 @@ inline void HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断是否有权限访问该目录
|
//判断是否有权限访问该目录
|
||||||
canAccessPath(_parser.Url(),true,[this,bClose,strFile,strMeun](bool canAccess,const CookieData::Ptr &cookie){
|
canAccessPath(_parser.Url(),true,[this,bClose,strFile,strMeun](bool canAccess,const HttpServerCookie::Ptr &cookie){
|
||||||
if(!canAccess){
|
if(!canAccess){
|
||||||
const_cast<string &>(strMeun) = kAccessDirUnauthorized;
|
const_cast<string &>(strMeun) = kAccessDirUnauthorized;
|
||||||
}
|
}
|
||||||
auto headerOut = makeHttpHeader(bClose,strMeun.size());
|
auto headerOut = makeHttpHeader(bClose,strMeun.size());
|
||||||
if(cookie){
|
if(cookie){
|
||||||
headerOut["Set-Cookie"] = cookie->getCookie(kCookieName);
|
headerOut["Set-Cookie"] = cookie->getCookie((*cookie)[kAccessPathKey]);
|
||||||
}
|
}
|
||||||
sendResponse(canAccess ? "200 OK" : "401 Unauthorized" , headerOut, strMeun);
|
sendResponse(canAccess ? "200 OK" : "401 Unauthorized" , headerOut, strMeun);
|
||||||
throw SockException(bClose ? Err_shutdown : Err_success,"close connection after access folder");
|
throw SockException(bClose ? Err_shutdown : Err_success,"close connection after access folder");
|
||||||
|
|
@ -499,7 +499,7 @@ inline void HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||||
|
|
||||||
auto parser = _parser;
|
auto parser = _parser;
|
||||||
//判断是否有权限访问该文件
|
//判断是否有权限访问该文件
|
||||||
canAccessPath(_parser.Url(),false,[this,parser,tFileStat,pFilePtr,bClose,strFile](bool canAccess,const CookieData::Ptr &cookie){
|
canAccessPath(_parser.Url(),false,[this,parser,tFileStat,pFilePtr,bClose,strFile](bool canAccess,const HttpServerCookie::Ptr &cookie){
|
||||||
//判断是不是分节下载
|
//判断是不是分节下载
|
||||||
auto &strRange = parser["Range"];
|
auto &strRange = parser["Range"];
|
||||||
int64_t iRangeStart = 0, iRangeEnd = 0;
|
int64_t iRangeStart = 0, iRangeEnd = 0;
|
||||||
|
|
@ -530,7 +530,7 @@ inline void HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cookie){
|
if(cookie){
|
||||||
httpHeader["Set-Cookie"] = cookie->getCookie(kCookieName);
|
httpHeader["Set-Cookie"] = cookie->getCookie((*cookie)[kAccessPathKey]);
|
||||||
}
|
}
|
||||||
//先回复HTTP头部分
|
//先回复HTTP头部分
|
||||||
sendResponse(canAccess ? pcHttpResult : "401 Unauthorized" , httpHeader,canAccess ? "" : kAccessFileUnauthorized);
|
sendResponse(canAccess ? pcHttpResult : "401 Unauthorized" , httpHeader,canAccess ? "" : kAccessFileUnauthorized);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
#include "RtmpMuxer/FlvMuxer.h"
|
#include "RtmpMuxer/FlvMuxer.h"
|
||||||
#include "HttpRequestSplitter.h"
|
#include "HttpRequestSplitter.h"
|
||||||
#include "WebSocketSplitter.h"
|
#include "WebSocketSplitter.h"
|
||||||
#include "CookieManager.h"
|
#include "HttpCookieManager.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
@ -119,7 +119,7 @@ private:
|
||||||
* @param is_dir path是否为目录
|
* @param is_dir path是否为目录
|
||||||
* @param callback 有权限或无权限的回调
|
* @param callback 有权限或无权限的回调
|
||||||
*/
|
*/
|
||||||
inline void canAccessPath(const string &path,bool is_dir,const function<void(bool canAccess,const CookieData::Ptr &cookie)> &callback);
|
inline void canAccessPath(const string &path,bool is_dir,const function<void(bool canAccess,const HttpServerCookie::Ptr &cookie)> &callback);
|
||||||
|
|
||||||
//获取用户唯一识别id,我们默认为ip+端口号
|
//获取用户唯一识别id,我们默认为ip+端口号
|
||||||
inline string getClientUid();
|
inline string getClientUid();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue