角色授权CSP202206-3

该文描述了一个角色授权系统的问题,包括用户、角色、操作、类型和资源的管理。代码实现主要涉及用户和组的关系处理,以及查询时对权限的检查,通过遍历用户和组的关联网络来判断权限是否满足。文章提到了在处理查询时的一些陷阱和优化点,如使用有向边表示关系,以及优化查询效率的技巧。
摘要由CSDN通过智能技术生成

问题描述

角色授权 题目链接

解题思路

大模拟,每一次查询时检查关联的组和用户是否满足要求。

代码实现

#include<iostream>
#include<vector>
#include<unordered_map>
#include<set>
#include<queue>
using namespace std;
int n,m,q;
unordered_map<string,int> nametoidx;
struct character {
	string name;
	unordered_map<string,int> opMap;
	unordered_map<string,int>  typeMap;
	unordered_map<string,int>  resourceMap;

} characters[1010];
struct user {
	string name;
	set<string> group;
};
struct action {
	user u;
	string op ;
	string type;
	string resource;
} actions[5010];

unordered_map<string,set<string>> relation;
unordered_map<string,set<string>> groupmember;


void getuser(){
	for(int i = 1; i <= n; i++) {
		string name;
		int nv;
		cin >> name>>nv;
		nametoidx[name] = i;
		characters[i].name = name;
		for(int j = 1; j <= nv; j++) {
			string op;
			cin >> op;
			characters[i].opMap[op] = 1;
		}
		int no;
		cin >> no;
		for(int j = 1; j <= no; j++) {
			string tp;
			cin >> tp;
			characters[i].typeMap[tp] = 1;
		}
		int nn;
		cin >> nn;
		for(int j = 1; j <= nn; j++) {
			string rs;
			cin >> rs;
			characters[i].resourceMap[rs] = 1;
		}
	}
}
void getrelation() {
	for(int i = 1; i <= m; i++) {
		string name;
		int ns;
		cin >> name>> ns;
		for(int j = 1; j<=ns; j++ ) {
			char t;
			string str;
			cin >> t >> str;
			if(t == 'u') {
				relation[str].insert(name);
			} else {
				groupmember[str].insert(name);
			}
		}
	}
}

void check(int i) {
	string op,type,resource;
	op =  actions[i].op;
	type = actions[i].type;
	resource = actions[i].resource;
	unordered_map<string,bool> st;
	bool opflag = false;
	bool typeflag = false;
	bool resourceflag= false;
	bool r = 0;
	//判断三个是否有权限
	for(auto grp : actions[i].u.group) {
		//遍历组
//		cout <<" check group "<<grp<<endl;
		for(auto mem : groupmember[grp]) {
			//遍历组的成员
			if(!st.count(mem)) {
				 opflag = false;
				 typeflag = false;
				 resourceflag= false;
//				cout << "check group "<<grp<<" member "<<mem<<endl;
				int memidx = nametoidx[mem];
				if(characters[memidx].opMap.count(op) || characters[memidx].opMap.count("*")) {
					opflag =1;
				}
				if(characters[memidx].typeMap.count(type) || characters[memidx].typeMap.count("*")) {
					typeflag =1;
				}
				if(characters[memidx].resourceMap.count(resource) || characters[memidx].resourceMap.size() == 0) {
					resourceflag =1;
				}
				r = r | (opflag && typeflag && resourceflag); 
				st[mem] = 1;

			}
		}
	}
	queue<string> q;
	q.push(actions[i].u.name);
	while(q.size()) {
		auto nm = q.front();
		q.pop();
		
		for(auto u : relation[nm]) {
			// 从相关联的中找
			// u是字符串
			if(!st.count(u)) {
				q.push(u);
				 opflag = false;
				 typeflag = false;
				 resourceflag= false;
				int memidx = nametoidx[u];
					if(characters[memidx].opMap.count(op) || characters[memidx].opMap.count("*")) {
					opflag =1;
				}
				if(characters[memidx].typeMap.count(type) || characters[memidx].typeMap.count("*")) {
					typeflag =1;
				}
				if(characters[memidx].resourceMap.count(resource)  || characters[memidx].resourceMap.size() == 0) {
					resourceflag =1;
				}
			r = r | (opflag && typeflag && resourceflag); 
				st[u] = 1;
			}
		}
	}
	if(r) {
		cout <<1<<endl;
	} else {
		cout<<0<<endl;
	}

}

void getaction() {
	for(int i = 1; i <= q; i++) {
		string name;
		int ng;
		cin >> name>> ng;
		actions[i].u.name = name;
		for(int j = 1; j<=ng; j++ ) {
			string str;
			cin >> str;
		
		actions[i].u.group.insert(str);
		}
		string a,b,c;
		cin >> a>>b>>c;
		actions[i].op = a, actions[i].type = b, actions[i].resource=c;
		check(i);
	}
}

int main() {
  	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin >> n >> m >> q;
	getuser();
	getrelation();
	getaction();

}

一些问题和踩到的坑

查询不用存到数组里,因为不同的查询是独立的。后面写了太长时间懒得改了,可能改了后能够快一点
访问成功需要关联的用户中三个条件同时满足
关联用户时建立的是一个有向边,因为建了无向边改了好久一直是50分
用ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)加速可以避免超时,不用的话只有70分
存关联的用户和组的时候可以用set或者map

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值