最近一直在做CMS系統(tǒng),發(fā)現(xiàn)一些內(nèi)容其實都是重復(fù)出現(xiàn)的,例如權(quán)限管理模塊。權(quán)限管理模塊就是為了管理用戶是否有權(quán)利訪問某個權(quán)限,如果不能則拒絕訪問。其實Java中已經(jīng)有很成熟的權(quán)限管理框架,例如 Shiro,Spring Security等,也推薦大家使用。但是一些設(shè)計上的東西還是要重復(fù)再造過輪子才能發(fā)現(xiàn)里面的精髓,所以這份代碼,供不太明白的同學(xué)也參考參考。
代碼分享在 Github 上,歡迎大家指出問題: https://github.com/yixiaoming/cms
下面我將詳細介紹一下這個簡單的權(quán)限管理模塊,以便大家可以拿去直接使用。
數(shù)據(jù)表
主要三張表
- t_user:用戶表,訪問系統(tǒng)的對象
- t_permission:權(quán)限表,每條記錄就是一個權(quán)限,也就是一個 url 地址
- t_group:用戶組表,一個組可以包含多個權(quán)限,用戶如果在這個組中,則享有所有權(quán)限
簡單例子
來個簡單的例子,例如一個CMS系統(tǒng)中,有一些權(quán)限:添加文章( /admin/article/add),查看文章( /admin/article/{id}),刪除文章( /admin/delete/{id}),修改文章( /admin/article/update/{id}),每個權(quán)限其實對應(yīng)一個controller的 requet 地址。這些內(nèi)容存放在 t_permission 中。
然后系統(tǒng)中有一些用戶都放在 t_user中,然后我可以為 每個user 分配一些權(quán)限,一個user叫 張三,我可以給他直接添加權(quán)限:查看文章。那么他只能查看,不能增刪改。
然后用戶組表可以看作一個部門,例如一個用戶組叫:文章管理組,那么這個組可以添加:文章的增刪改查4項權(quán)限。現(xiàn)在我再將 user分配到 文章管理組 中,那么張三就擁有了 文章的增刪改查的所有權(quán)限。
最主要的思想就是:用戶的權(quán)限,可以直接分配,也可以通過用戶組來分配,用戶的所有權(quán)限就是兩者的并集
框架
- Spring 4.26
- Hibernate 5.10
- Java 8
例子采用 SpringMVC + Hibernate + Bootstrap搭建,簡單實用,對于小項目使用絕對沒有問題。
然后里面也用到了一些開源的Web前端項目,例如SB-Admin,Bootstrap Multiselect,MetisMenu,Bootstrap Validation等,由于我本來不是做前端的,所以UI上的東西只能借助開源項目來完成。下面展示一下效果:
登陸頁
用戶列表頁,用戶組列表頁,權(quán)限列表頁 都類似
用戶添加,修改頁:
選擇權(quán)限
選擇用戶組
當(dāng)選定了權(quán)限和用戶組,那么用戶的權(quán)限就是 權(quán)限+角色組所有的權(quán)限 的并集。
登陸成功后將所有權(quán)限放在session中:
LoginController
List<Permission> permissions = userService.listUserPermissions(user.getId());
List<Integer> gids = userService.listUserGids(user.getId());
List<Permission> groupPermissions = groupService.listGroupsPermissions(ListUtil.list2array(gids));
for (Permission p : groupPermissions) {
if (!permissions.contains(p)) {
permissions.add(p);
}
}
request.getSession().setAttribute(Constant.LOGIN_USER, user);
request.getSession().setAttribute(Constant.LOGIN_PERMISSIONS, permissions);
然后寫兩個個攔截器,一個判斷登錄,一個判斷權(quán)限,每次訪問鏈接前先判斷是否有這個權(quán)限,如果沒有則拋出異常。這里有一點還需要注意,如果用戶的類型使 Admin 的話,那么默認就擁有所有權(quán)限,所以不需要驗證。通過 user 的 isAdmin 字段判斷
LoginInterceptor
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
User user = (User) request.getSession().getAttribute(Constant.LOGIN_USER);
if (request.getRequestURL().toString().contains("/admin")) {
if (user == null) {
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
}
return true;
}
PermissionInterceptor
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
String url = request.getRequestURL().toString();
if (url.contains("/admin")) {
List<Permission> permissions = (List<Permission>) request.getSession().getAttribute(Constant.LOGIN_PERMISSIONS);
User user = (User) request.getSession().getAttribute(Constant.LOGIN_USER);
if (permissions == null || user == null) {
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
// 如果是admin,就不需要權(quán)限驗證
if (user.getAdmin()) {
return true;
}
boolean hasPermission = false;
for (Permission permission : permissions) {
if (url.contains(permission.getUrl())) {
hasPermission = true;
break;
}
}
if (!hasPermission) {
throw new CmsException("沒有權(quán)限訪問:" + url);
}
}
return true;
}
總結(jié)
這里洋洋灑灑的寫了一些權(quán)限模塊中的內(nèi)容,只是里面的主線,細節(jié)的代碼大家可以參考Github上的代碼地址鏈接,大神略過。希望能給正在學(xué)習(xí)這個內(nèi)容的同學(xué)一點幫助,反正造這個輪子,我學(xué)到了不少。。。