servlet極簡單權限攔截設計處理
在java web的開發中 遇到的極其簡單的權限控制,整個小項目就分為四五種用戶的權限角色,因此不想考慮使用框架以及數據庫建角色表,菜單表,操作表等來完成權限設計,而是采用反射,注解的簡單方法完成。
核心代碼
BaseServlet.java文件
import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.zk.annotation.Permission; import com.zk.bean.User;/**
- servlet基類
- @Description TODO
- @author zk
- @version 1.0
@date 2015-4-9 下午4:53:11 */ @SuppressWarnings("all") public abstract class BaseServlet extends HttpServlet { private static final long serialVersionUID = -6898295798172047477L; protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException { /** * 思路1 .根據method參數 處理 2.使用反射調用 * 2 加入簡單的權限判斷(當然也可以通過過濾器設計 攔截實現) * 由于本案例不需要復雜的權限設計,故沒有采用分別建幾張表 來存角色,菜單,操作等信息,只用在用戶表添加一個字段 level 0 1,4,7來處理 * 0:此用戶無效(軟刪除)相當于已經刪除 * 1: 普通訪客等級 無需登錄 主要是前端的信息瀏覽 * 4 :會員等級 可以登錄,進行相關操作 * 7 :頂級管理員操作 * 中間預留一些字段做不同的權限。 * 3權限判斷的核心思路: * 1> 建一個 BaseServlet 父類 讓之類Servlet繼承 * 2> 在BaseServlet 中重寫service 方法通過反射 以及在之類中的方法操作上加自定義注解【見下文自定義注解文件】 eg:@Permission(level=3) * 3> 在service 方法中通過 request.getParmenter("method") 獲取在子類中對應的方法操作名稱,并反射獲取該方法名稱 * 上面的注解信息 level * 4> 對注解信息 以及用戶的登錄狀態 和用戶的level狀態進行判斷 * 對于有些操作需要登錄 或者權限等級較高的 就可以重定向處理攔截權限 * 0等級忽略 由于1 為 普通權限 故先判斷是否為普通權限 就是普通網站訪問者權限 * 當操作方法的leve為1 放行 * 不為1 說明需要更高的用戶權限 * 那么首先判斷是否登錄 沒有登錄的 返回登錄 * 登錄成功的 獲取登錄用戶的leve狀態 和請求該方法的操作level權限等級對比 * 如果用戶的leve小于該方法操作的 就攔截 返回,反之就可以進行方法操作 * * */ // 只處理了post的亂碼問題,get自行處理 req.setCharacterEncoding("utf-8"); // 只是處理 了 字符流的問題,字節流自行處理 resp.setContentType("text/html;charset=utf-8"); String methodName = req.getParameter("method"); // 判斷是否有方法 if (methodName == null || methodName.trim().isEmpty()) { throw new RuntimeException("親!請傳入method的參數"); } Class clazz = this.getClass(); Method method = null; try { method = clazz.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); // 注意 此處利用注解 獲取 每一個請求方法上的注解信息 Permission info = method.getAnnotation(Permission.class); // 如果獲取到注解信息 if (info != null) { int level = info.level();// 訪問此操作需要的權限級別 if (level != 1) { // level 級別為默認的 最低等級 故無需處理 跳過 // level !=1 說明需要登錄 以及更高等級的用戶權限 User user = (User) req.getSession() .getAttribute("backUser"); // 判斷是否登錄 if (req.getSession().getAttribute("backUser") == null) { String contextPath = getServletContext() .getContextPath(); resp.getWriter() .print("親,您還沒有登錄,請<a href='" + contextPath + "/index.jsp' target='_parent'>登錄</a>!"); return; } else { // 登錄成功 判斷用戶所擁有等級與 此操作的等級 if (user.getLevel() < level) { String contextPath = getServletContext() .getContextPath(); resp.getWriter() .print("對不起,你暫且無權限操作,請<a href='" + contextPath + "/index.jsp' target='_parent'>登錄</a>申請為會員!"); return; } } } } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("親!傳入method的參數錯誤"); } try { String result = (String) method.invoke(this, req, resp); if (result != null && !result.trim().isEmpty()) { req.getRequestDispatcher(result).forward(req, resp); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }
}
}</pre>
自定義注解文件Permission.java
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /**
- 自定義權限注解
- @Description TODO
- @author zk
- @version 1.0
- @date 2015-4-12 下午9:34:46
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD,ElementType.TYPE})
public @interface Permission {
int level ();
}</pre>
子類Servlet的操作 使用示例:
import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map;
import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import com.zk.annotation.Permission; import com.zk.bean.Customer; import com.zk.bean.Message; import com.zk.bean.MessageType; import com.zk.bean.MessageTypeLev; import com.zk.bean.PageBean; import com.zk.bean.User; import com.zk.service.CustomerService; import com.zk.service.MessageService; import com.zk.service.MessageTypeService;
/**
- 和信息相關的控制器 繼承自定義的BaseServlet
- @Description TODO
- @author zk
- @version 1.0
- @date 2015-4-11 上午10:21:56
*/
public class MessageServlet extends BaseServlet {
/**
- 通過id刪消息
- @param request
- @param response
- @return
- @throws ServletException
- @throws IOException
*/
@Permission(level = 3)// 注意 :注解的使用 不同的操作設置不同的值
public String deleteById(HttpServletRequest request,
String id = request.getParameter("id"); String pageCode = request.getParameter("pageCode"); String totalPage = request.getParameter("totalPage"); MessageService cs = new MessageService(); cs.deleteById(id); int pg = 1; if (Integer.parseInt(totalPage) % Integer.parseInt(pageCode) == 0) {HttpServletResponse response) throws ServletException, IOException {
} return "/message?method=listMsg&pageCode=" + pg; } }</pre>if (Integer.parseInt(pageCode) > 1) { pg = Integer.parseInt(pageCode) - 1; } else { // 已結沒有信息了 }
附上user用戶表設計的結構
-- ---------------------------- -- Table structure for t_customer
CREATE TABLE t_customer
(
id
varchar(40) NOT NULL,
username
varchar(20) DEFAULT NULL,
gender
varchar(10) DEFAULT NULL,
birthday
varchar(20) DEFAULT NULL,
cellphone
varchar(20) DEFAULT NULL,
email
varchar(40) DEFAULT NULL,
love
varchar(100) DEFAULT NULL,
type
varchar(40) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;</pre>
總結:反射 注解 簡單繼承 統一處理。東西和思路比較粗糙,只是為了實現寫簡單功能,希望批判接受和建議,謝謝。