Võ Văn Hải's blog

Chỉ có một điều tuyệt đối đó là mọi thứ đều tương đối…

Cấp phát quyền cho chương trình C/C++ theo hướng cấu trúc

Trong bài này chúng ta thử làm quen với 1 khái niệm cấp phát quyền trong C++ theo hướng cấu trúc.
Ý tưởng chính là tạo ra 1 danh sách người sử dụng, một danh sách các role(mỗi role gồm nhiều người sử dụng), một danh sách các chức năng của 1 chương trình cần cấp phát quyền. Sau đó ta tiến hành cấp quyền bằng cách: mỗi quyền ta sẽ cấp(grant) hoặc cấm(denied) cho một role truy xuất lên 1 chức năng.
Do là hướng tiếp cận cấu trúc nên những ai quen với cách OOP sẽ rất khó chịu(lúc đầu nó cũng làm tôi bực mình :)). Ngoài ra tôi cũng không chắc nó là giải pháp tốt nhất nên chúng ta có thể cùng tranh luận cho vấn đề được sáng tỏ.
Môi trường tích hợp phát triển(IDE) ở đây là C-Free.
Thư mục lưu trữ có tên E:\\VoVanHai\\WordPress\\Com


Đầu tiên ta xây dựng file User.cpp để đặc tả cho 1 user và danh sách các user. Code như sau:

#include<iostream.h>
#include<string.h>
#include<fstream.h>
//Cau truc cua 1 user
struct User{
    char userName[30];
    char password[30];
    char role[20];
    int status;//-1:disable;1-enable
};

struct UserNode{
    User data;
    UserNode *next;
    UserNode *prev;
};
//danh sach user
struct UserList{
    UserNode *head;
    UserNode *tail;
};
/**
* Ham khoi tao 1 danh sach user
*/
void InitUserList(UserList&ul){
    ul.head=NULL;
    ul.tail=NULL;
}
/**
* Ham tao 1 node khi co thong tin user
*/
UserNode* createUserNode(User user){
    UserNode *n=new UserNode;
    if(n==NULL){cout<<"\n***Not enough Memory***\n";return NULL;}
    n->data=user;
    n->next=n->prev=NULL;
}
/**
    Them 1 user node vao cuoi danh sach
    Tra ve True neu them duoc, False neu khong du bo nho
*/
bool InsertNewUser(UserList&ul,UserNode*node){
    if(node==NULL)return false;
    if(ul.head==NULL)
        ul.head=ul.tail=node;
    else{
        ul.tail->next=node;
        node->prev=ul.tail;
        ul.tail=node;
        }
    return true;
}
/**
* Tim kiem user theo ten
*/
User* getUserByUserName(UserList ul,char userName[]){
	UserNode *un=ul.head;
    while(un!=NULL){
    	User* user=&(un->data);
    	if(strcmpi(user->userName,userName)==0)
    		return user;
   	 	un=un->next;
    }
    return NULL;
}
//In danh sach cac user
void PrintAllUsers(UserList ul){
    UserNode *un=ul.head;
    while(un!=NULL){
        User user=un->data;
        cout<<user.userName<<"\t"<<user.role<<"\t"<<user.status<<endl;
        un=un->next;
    }
}

//ham ghi du lieu xuong file
void write2file(char * filename, UserList ds){
	ofstream fs(filename, ios::binary | ios::out );//| ios::app
	UserNode*t=ds.head;
	 while(t!=NULL){
	 	fs.write((char*)&t->data,sizeof(User));
	 	t=t->next;
      }    
    fs.close();
}
///hàm doc du lieu tu file
void readfromfile(char * filename, UserList &ds){
	InitUserList(ds);
	ifstream infile(filename,ios::in|ios::binary);
	if(infile!=NULL){
		User data;
		infile.read((char*)&data,sizeof(User));
	    while(!infile.eof()){
    		UserNode*n=createUserNode(data);
	       InsertNewUser(ds,n);
	       infile.read((char*)&data,sizeof(User));
	      } 
	}
    infile.close();
}
//Cac ham khac neu co the
//....
 

Tiếp theo ta xây dựng một danh sách các Role để tiện việc cấp quyền(File Role.cpp). Thay vì cấp cho từng user ta chỉ cần cấp cho role, như vậy tất cả các user thuộc role đó sẽ được cấp quyền (giống như ta thấy các user group trong hệ điều hành).
Chú ý nếu biên dịch cho riêng file này thì ta bỏ comment cho include đến file User.cpp

#include<iostream.h>
#include<string.h>
#include<fstream.h>
//#include "E:\\VoVanHai\\WordPress\\Com\\User.cpp"
struct Role{
    char roleName[30];
    UserList userList;
};

struct RoleNode{
    Role data;
    RoleNode *next;
    RoleNode *prev;
};
//danh sach cac role
struct RoleList{
    RoleNode *head;
    RoleNode *tail;
};
//khoi tao
void InitRoleList(RoleList&ul){
    ul.head=NULL;
    ul.tail=NULL;
}

RoleNode* createRoleNode(Role role){
    RoleNode *n=new RoleNode;
    if(n==NULL){cout<<"\n***Not enough Memory***\n";return NULL;}
    n->data=role;
    n->next=n->prev=NULL;
}
//Them 1 role moi
bool InsertNewRole(RoleList&ul,RoleNode*node){
    if(node==NULL)return false;
    if(ul.head==NULL)
        ul.head=ul.tail=node;
    else{
        ul.tail->next=node;
        node->prev=ul.tail;
        ul.tail=node;
        }
    return true;
}
/**
*	Them 1 user vao role
*	Tra ve True neu them duoc, false neu da ton tai user trong role
*/
bool AddUser2Role(RoleList&rl, char roleName[],User user){
	RoleNode *t=rl.head;
	while(t!=NULL){
		Role role=t->data;
		if(strcmpi(role.roleName,roleName)==0){
			//UserList ul=role.userList;
			UserNode *un=createUserNode(user);
			InsertNewUser(role.userList,un);
			break;
		}
		t=t->next;
	}
}
/**
*	Lay danh sach cac User theo ROle
*/
UserList* GetUserByRole(RoleList rl,char roleName[]){
	RoleNode *t=rl.head;
	while(t!=NULL){
		Role role=t->data;
		if(strcmpi(role.roleName,roleName)==0){
			UserList *ul=&(role.userList);
			return ul;
		}
		t=t->next;
	}
	return NULL;
}
//.....

Tiếp theo ta xây dựng một danh sách các chức năng cần để cấp phát quyền(File Function.cpp). Code như sau:

#include<fstream.h>
#include<string.h>
#include<iostream.h>
struct Function{
	char functionName[50];
	char functionDesc[100];
};
struct FunctionNode{
	Function data;
	FunctionNode*next;
	FunctionNode*prev;
};
struct FunctionList{
	FunctionNode*head;
	FunctionNode*tail;
};

void InitFunctionList(FunctionList&fl){
	fl.head=fl.tail=NULL;
}

FunctionNode* createFunctionNode(Function func){
    FunctionNode *n=new FunctionNode;
    if(n==NULL){cout<<"\n***Not enough Memory***\n";return NULL;}
    n->data=func;
    n->next=n->prev=NULL;
}

bool InsertNewFunction(FunctionList&fl,FunctionNode*node){
    if(node==NULL)return false;
    if(fl.head==NULL)
        fl.head=fl.tail=node;
    else{
        fl.tail->next=node;
        node->prev=fl.tail;
        fl.tail=node;
        }
    return true;
}

Function* getFunctionByUserName(FunctionList ul,char functionName[]){
	FunctionNode *un=ul.head;
    while(un!=NULL){
    	Function* user=&(un->data);
    	if(strcmpi(user->functionName,functionName)==0)
    		return user;
   	 	un=un->next;
    }
    return NULL;
}
//............

Ta lại xây dựng 1 danh sách các chính sách(policy) của ta(File Policy.cpp). Mỗi policy được qui định là ứng với mỗi chức năng ta cấp cho role nào. Lưu ý là mỗi chức năng có thể cấp cho nhiều role và 1 role có thể được cấp nhiều chức năng. Để thuận tiện, role nào ta muốn được cấp tất cả quyền trên tất cả các chức năng thì ta chỉ cần để bằng 1 ký tự thay thế ‘*’.(Chú ý nếu muốn biên dịch độc lập thì bỏ các dấu ghi chú của các dòng import)
Code như sau:
[/sourcecode]
#include
#include
#include
//#include “E:\\VoVanHai\\WordPress\\Com\\User.cpp”
//#include “E:\\VoVanHai\\WordPress\\Com\\Function.cpp”
//#include “E:\\VoVanHai\\WordPress\\Com\\Role.cpp”
struct Policy{
char roleName[30];
char functionName[100];
int status;//1-granted;0-denied
};

struct PolicyNode{
Policy data;
PolicyNode*next;
PolicyNode*prev;
};
struct PolicyList{
PolicyNode*head;
PolicyNode*tail;
};

void InitPolicyList(PolicyList&pl){
pl.head=pl.tail=NULL;
}

PolicyNode* createPolicyNode(Policy pol){
PolicyNode *n=new PolicyNode;
if(n==NULL){cout<data=pol;
n->next=n->prev=NULL;
}

bool InsertNewPolicy(PolicyList&pl,PolicyNode*node){
if(node==NULL)return false;
if(pl.head==NULL)
pl.head=pl.tail=node;
else{
pl.tail->next=node;
node->prev=pl.tail;
pl.tail=node;
}
return true;
}
/**
* Kiem tra 1 chuc nang co duoc cap cho user khong
Tra ve 1 neu duoc cap; 0 neu khong duoc cap; -1 neu khong noi gi
*/
int checkPolicyGrantedByUserName(PolicyList pl,char roleName[],char functionName[]){
PolicyNode *pn=pl.head;
while(pn!=NULL){
Policy* pol=&(pn->data);
if(strcmpi(pol->roleName,roleName)==0
&& strcmpi(pol->functionName,functionName)==0)
if(pol->status==1)
return 1;
else
return 0;
pn=pn->next;
}
return -1;
}
/**
* cap quyen cho role
* param: roleName:ten role can cap quyen
* functionname:ten chuc nang can cap quyen
* status: 1-cap quyen; 0-ca^’m quyen
*/
bool GrantPolicy2Role(PolicyList &pl,char roleName[],char functionName[],int status){
PolicyNode *pn=pl.head;
while(pn!=NULL){
Policy* pol=&(pn->data);
if(strcmpi(pol->roleName,roleName)==0
&& strcmpi(pol->functionName,functionName)==0){
pol->status=status;
return true;
}
pn=pn->next;
}
return false;
}


<hr/>
Tiếp theo ta xây dựng 1 module cho Admin để có thể thêm người dùng, thêm role, thêm chức năng của chương trình, cấp quyền,... (File AdminModule.cpp)

#include<string.h>
#include<fstream.h>
#include<iostream.h>
#include "E:\\VoVanHai\\WordPress\\Com\\User.cpp"
#include "E:\\VoVanHai\\WordPress\\Com\\Function.cpp"
#include "E:\\VoVanHai\\WordPress\\Com\\Role.cpp"
#include "E:\\VoVanHai\\WordPress\\Com\\Policy.cpp"

//Gia su ta co cac quyen cua chuong trinh o day
FunctionList getSampleFunctionList(){
	FunctionList fl;
	Function f1;strcpy(f1.functionName,"f1");strcpy(f1.functionDesc,"f1");
	Function f2;strcpy(f2.functionName,"f2");strcpy(f2.functionDesc,"f2");
	Function f3;strcpy(f3.functionName,"f3");strcpy(f3.functionDesc,"f3");
	Function f4;strcpy(f4.functionName,"f4");strcpy(f4.functionDesc,"f4");
	Function f5;strcpy(f5.functionName,"f5");strcpy(f5.functionDesc,"f5");
	Function f6;strcpy(f6.functionName,"f6");strcpy(f6.functionDesc,"f6");
	Function f7;strcpy(f7.functionName,"f7");strcpy(f7.functionDesc,"f7");
	FunctionNode *n1=createFunctionNode(f1);
	FunctionNode *n2=createFunctionNode(f2);
	FunctionNode *n3=createFunctionNode(f3);
	FunctionNode *n4=createFunctionNode(f4);
	FunctionNode *n5=createFunctionNode(f5);
	FunctionNode *n6=createFunctionNode(f6);
	FunctionNode *n7=createFunctionNode(f7);
	InsertNewFunction(fl,n1);InsertNewFunction(fl,n2);
	InsertNewFunction(fl,n3);InsertNewFunction(fl,n4);
	InsertNewFunction(fl,n5);InsertNewFunction(fl,n6);
	InsertNewFunction(fl,n7);
	return fl;
}
//danh sach cac nguoi dung ban dau
UserList getSampleUserList(){
	UserList ul;InitUserList(ul);
    User us1;strcpy(us1.userName,"teo");strcpy(us1.password,"123");
    strcpy(us1.role,"admin");us1.status=1;
    User us2;strcpy(us2.userName,"ty");strcpy(us2.password,"123");
    strcpy(us2.role,"user");us2.status=1;
    User us3;strcpy(us3.userName,"men");strcpy(us3.password,"123");
    strcpy(us3.role,"guest");us3.status=1;
    UserNode *n1=createUserNode(us1);
    UserNode *n2=createUserNode(us2);
    UserNode *n3=createUserNode(us3);
    InsertNewUser(ul,n1);
    InsertNewUser(ul,n2);
    InsertNewUser(ul,n3);	
	return ul;
}
//danh sach cac role ban dau
RoleList getSampleRoleList(){
	RoleList rl;InitRoleList(rl);
    UserList ul=getSampleUserList();    
    Role r;strcpy(r.roleName,"admin");r.userList=ul;
    InsertNewRole(rl,createRoleNode(r));	
	return rl;
}
//Cap quyen cho role
PolicyList getSamplePolicyList(){
	PolicyList pl;InitPolicyList(pl);
	Policy p1;strcpy(p1.roleName,"admin");strcpy(p1.functionName,"*");p1.status=1;
	Policy p2;strcpy(p2.roleName,"user");strcpy(p2.functionName,"f1");p2.status=1;
	Policy p3;strcpy(p3.roleName,"user");strcpy(p3.functionName,"f2");p3.status=1;
	Policy p4;strcpy(p4.roleName,"user");strcpy(p4.functionName,"f3");p4.status=1;
	Policy p5;strcpy(p5.roleName,"user");strcpy(p5.functionName,"f4");p5.status=1;
	Policy p6;strcpy(p6.roleName,"user");strcpy(p6.functionName,"f5");p6.status=1;
	Policy p7;strcpy(p7.roleName,"guest");strcpy(p7.functionName,"f6");p7.status=1;
	Policy p8;strcpy(p8.roleName,"guest");strcpy(p8.functionName,"f3");p8.status=1;
	Policy p9;strcpy(p9.roleName,"guest");strcpy(p9.functionName,"f4");p9.status=1;
	PolicyNode *n1=createPolicyNode(p1);	PolicyNode *n2=createPolicyNode(p2);
	PolicyNode *n3=createPolicyNode(p3);	PolicyNode *n4=createPolicyNode(p4);
	PolicyNode *n5=createPolicyNode(p5);	PolicyNode *n6=createPolicyNode(p6);
	PolicyNode *n7=createPolicyNode(p7);	PolicyNode *n8=createPolicyNode(p8);
	PolicyNode *n9=createPolicyNode(p9);
	InsertNewPolicy(pl,n1);	InsertNewPolicy(pl,n2);	InsertNewPolicy(pl,n3);
	InsertNewPolicy(pl,n4);	InsertNewPolicy(pl,n5);	InsertNewPolicy(pl,n6);
	InsertNewPolicy(pl,n7);	InsertNewPolicy(pl,n8);	InsertNewPolicy(pl,n9);
	return pl;
}
/**
*	Dang nhap he thong
*	Tra ve NULL neu khong ton tai user
*	Tra ve user neu dung us va password
*	truong hop dung us,psw nhung status =0 (user disable) thi xu ly ben tren
*/
User* logon(UserList ul,char userName[],char password[]){
	//User user;strcpy(user.userName,userName);strcpy(user.password,password);
	User *us=getUserByUserName(ul,userName);
	if(us==NULL) return NULL;
	if(strcmp(password,us->password)==0)
		return us;
	return NULL;
}
/**
*	Ham kiem tra 1 role co duoc cap quyen tren 1chuc nang hay khong
*
*/
bool isFunctionGrant4Role(PolicyList pl,char roleName[],char functionName[]){
	PolicyNode *pn=pl.head;
	while(pn!=NULL){
		Policy pol=pn->data;
		if((strcmpi(pol.roleName,roleName)==0 &&pol.functionName[0]=='*'))
			return true;
		if((strcmpi(pol.roleName,roleName)==0 && strcmpi(pol.functionName,functionName)==0))
			return true;
		pn=pn->next;	
	}
	return false;	
}

OK. Như vậy ta đã xong phần cơ bản. Bây giờ ta thử kết quả của việc xây dựng cơ bản.
Giả sử ta có 1 chương trình với 7 chức năng có tên từ f1 đến f7, và việc cấp quyền đã được liệt kê trong AdminModule. Đầu tiên, người dùng phải đăng nhập với tài khoản của họ, sau đó sẽ gọi chức năng. Nếu chức năng nào bị cấm sẽ thông báo tương ứng. Code như sau (File MySampleProgram.cpp):

#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include "E:\\VoVanHai\\WordPress\\Com\\AdminModule.cpp"
int main(int argc, char *argv[])
{
	char us[30],ps[30];
	cout<<"Vui long dang nhap he thong\n";
	cout<<"\t Enter User Name:";cin.getline(us,30);
	cout<<"\t Enter Password:";cin.getline(ps,30);
	UserList ul=getSampleUserList();
	User*user=logon(ul,us,ps);//User dang nhap
	if(user==NULL){
		cerr<<"Ban da nhap sai User Name/Password\n";
		return -1;
	}
	else if(user->status==-1){
		cerr<<"Tai khoan cua ban da bi disable\n";
		return 0;
	}
	//else
	cout<<"logon successfull...\n";
	cout<<"nhan 1 phim bat ky de tiep tuc";
	getchar();
	system("cls");
	//thuc hien nap phan quyen
	PolicyList pl=getSamplePolicyList();
	//================================
	char *f[]={"f1","f2","f3","f4","f5","f6","f7"};	
	do{
		cout<<"SAMPLE APP WITH PRIVILEGE POLICY\n";
		cout<<"1. Chuc nang 1\n";
		cout<<"2. Chuc nang 2\n";
		cout<<"3. Chuc nang 3\n";
		cout<<"4. Chuc nang 4\n";
		cout<<"5. Chuc nang 5\n";
		cout<<"6. Chuc nang 6\n";
		cout<<"7. Chuc nang 7\n";
		cout<<"8. Log out\n";
		cout<<"0. Thoat chuong trinh\n";
		cout<<"***Chon lua cua ban:";
		int tl;cin>>tl;
		if(user!=NULL)
			cout<<"\n-----Your role: "<<user->role<<"\n";
		else{
			cout<<"\n-----Please log on to play with app\n";
			return 1;
		}
		switch(tl){
			case 1:{
				if(isFunctionGrant4Role(pl,user->role,"f1")==true){
					cout<<"\nYou can play with this Function\n";
				}
				else{
					cout<<"\nYou are denied from this function\n";
				}
			}
			break;
			case 2:{
				if(isFunctionGrant4Role(pl,user->role,"f2")==true){
					cout<<"\nYou can play with this Function\n";
				}
				else{
					cout<<"\nYou are denied from this function\n";
				}
			}
			break;
			case 3:{
				if(isFunctionGrant4Role(pl,user->role,"f3")==true){
					cout<<"\nYou can play with this Function\n";
				}
				else{
					cout<<"\nYou are denied from this function\n";
				}
			}
			break;
			case 4:
				if(isFunctionGrant4Role(pl,user->role,"f4")==true){
					cout<<"\nYou can play with this Function\n";
				}
				else{
					cout<<"\nYou are denied from this function\n";
				}
			break;
			case 5:{
				if(isFunctionGrant4Role(pl,user->role,"f5")==true){
					cout<<"\nYou can play with this Function\n";
				}
				else{
					cout<<"\nYou are denied from this function\n";
				}
			}
			break;
			case 6:
			{
				if(isFunctionGrant4Role(pl,user->role,"f6")==true){
					cout<<"\nYou can play with this Function\n";
				}
				else{
					cout<<"\nYou are denied from this function\n";
				}
			}break;
			case 7:
				{
				if(isFunctionGrant4Role(pl,user->role,"f7")==true){
					cout<<"\nYou can play with this Function\n";
				}
				else{
					cout<<"\nYou are denied from this function\n";
				}
			}
			break;
			case 8:{
				cout<<"\nLog you out. Quit and replay the app\n";
				delete user;user=NULL;
			}
			break;
			case 0:exit(1);
			default:
			cerr<<"***Chon lua khong hop le***\n";
		}
		getchar();
		system("cls");
	}while(true);
	return 0;
}

Trong code này chưa thực hiện việc lưu người dùng,chức năng,… xuống file. Khi chương trình bắt đầu thì load lên và khi chương trình kết thúc thì lưu lại. Code tôi đã viết trong file User.cpp cho việc lưu, đọc; các file khác thì bạn hoàn toàn tương tự có thể copy và chỉnh sửa chút ít.
Chúc các bạn thành công!

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.