基于注解和拦截器的权限控制
2015-12-15 17:21
465 查看
互联网中各种各样的系统非常多,但是始终都离不开权限控制。一个好的权限控制对系统的安全性有着极大的提升,最近写了一个简单实用的权限验证的小例子,在这里分享下我的想法。
我们使用注解+拦截器来实现权限控制,以注解来标示某个类或者方法的权限,用拦截器来验证用户的权限,把权限控制细化到了每个方法。
所需材料:
注解:PrivCtrl
控制器:UserController
Bean:User,Request
枚举:PrivCtrlType
工具:RequestFactory,HttpClientUtil,SessionUtil
拦截器:PrivCtrlInterceptor
首先我们需要一个枚举类来保存我们系统所拥有的各种权限类型:
紧接着我们需要定义一个注解用来标示类和方法的权限:
使用一个用户对象来记录用户信息,一个Session工具来操作当前会话的用户以及其他信息:
还需要一个对象来记录请求信息,一个工厂来实例化一个请求信息:
我们首先通过拦截器验证当前用户是否有请求权限:
权限验证不通过时保存请求信息并跳转到登录页面进行登录:
登录过后通过自制的Http客户端工具跳转到保存的请求页面:
总结:
存在问题:Ajax请求的接口没有做额外处理,暂时还没有完善
解决方案:拦截器中判断是否是请求接口,如果是请求接口,则返回权限不足,需要封装Ajax请求方法,未登录时跳转到登录页面并记录当前URL
我们使用注解+拦截器来实现权限控制,以注解来标示某个类或者方法的权限,用拦截器来验证用户的权限,把权限控制细化到了每个方法。
所需材料:
注解:PrivCtrl
控制器:UserController
Bean:User,Request
枚举:PrivCtrlType
工具:RequestFactory,HttpClientUtil,SessionUtil
拦截器:PrivCtrlInterceptor
首先我们需要一个枚举类来保存我们系统所拥有的各种权限类型:
package com.liyh.enumeration; public enum PrivCtrlType { /** 游客 */ PUBLIC(0), /** 会员 */ MEMBER(1); private int code; private PrivCtrlType(int code) { this.code = code; } @Override public String toString() { return String.valueOf(code); } }
紧接着我们需要定义一个注解用来标示类和方法的权限:
package com.liyh.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import com.liyh.enumeration.PrivCtrlType; @Retention(RetentionPolicy.RUNTIME) public @interface PrivCtrl { PrivCtrlType[] value() default {PrivCtrlType.PUBLIC}; }
使用一个用户对象来记录用户信息,一个Session工具来操作当前会话的用户以及其他信息:
package com.liyh.domain; import com.liyh.enumeration.PrivCtrlType; public class User { private String id; private String username; private String password; private String type = PrivCtrlType.MEMBER.toString(); public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
package com.liyh.utils; import java.util.Date; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import com.liyh.domain.User; public class SessionUtil { private static final String KEY_USER = "User"; private static final String KEY_LOGIN_TIME = "loginTime"; public static void invalid() { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes != null) { requestAttributes.removeAttribute(KEY_USER, RequestAttributes.SCOPE_SESSION); requestAttributes.removeAttribute(KEY_LOGIN_TIME, RequestAttributes.SCOPE_SESSION); } } public static void login(User user) { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes != null) { requestAttributes.setAttribute(KEY_USER, user, RequestAttributes.SCOPE_SESSION); requestAttributes.setAttribute(KEY_LOGIN_TIME, new Date(), RequestAttributes.SCOPE_SESSION); } } public static User getCurrentUser() { User user = null; RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes != null) { user = (User)requestAttributes.getAttribute(KEY_USER, RequestAttributes.SCOPE_SESSION); } return user; } public static String getUserId() { User user = getCurrentUser(); if (user != null) { return user.getId(); } return null; } public static Date getlastLoginTime() { Date lastLoginTime = null; RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes != null) { lastLoginTime = (Date) requestAttributes.getAttribute(KEY_LOGIN_TIME, RequestAttributes.SCOPE_SESSION); } return lastLoginTime; } }
还需要一个对象来记录请求信息,一个工厂来实例化一个请求信息:
package com.liyh.domain.utils; import java.util.Map; /* 请求参数 */ public class Request { private boolean send; private String url; private String method; private Map<String, String[]> parameterMap; public boolean isSend() { return send; } public void setSend(boolean send) { this.send = send; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public Map<String, String[]> getParameterMap() { return parameterMap; } public void setParameterMap(Map<String, String[]> parameterMap) { this.parameterMap = parameterMap; } }
package com.liyh.factory; import javax.servlet.http.HttpServletRequest; import com.liyh.domain.utils.Request; public class RequestFactory { public static Request createReuqest(HttpServletRequest request) { Request myRequest = new Request(); myRequest.setUrl(request.getRequestURL().toString()); myRequest.setMethod(request.getMethod()); myRequest.setParameterMap(request.getParameterMap()); return myRequest; } }
我们首先通过拦截器验证当前用户是否有请求权限:
package com.liyh.interceptor; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.liyh.annotation.PrivCtrl; import com.liyh.domain.User; import com.liyh.enumeration.PrivCtrlType; import com.liyh.factory.RequestFactory; import com.liyh.utils.SessionUtil; /** 权限拦截器 */ public class PrivCtrlInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } PrivCtrl privCtrl = getPrivCtrl((HandlerMethod) handler); if (isLoginRequired(privCtrl) && !verifyPrivCtrl(privCtrl)) { loginRedirect(request, response); } return true; } /** 获取权限注解 */ private PrivCtrl getPrivCtrl(HandlerMethod method) { PrivCtrl ctrlAnnnotation = method.getMethodAnnotation(PrivCtrl.class); if (ctrlAnnnotation == null) { ctrlAnnnotation = method.getBeanType().getAnnotation(PrivCtrl.class); } return ctrlAnnnotation; } /** 判断是否需要登录 */ private boolean isLoginRequired(PrivCtrl privCtrl) { if (privCtrl == null) { return false; } for (PrivCtrlType privCtrlType : privCtrl.value()) { if (privCtrlType != PrivCtrlType.PUBLIC) { return true; } } return false; } /** 权限验证 */ private boolean verifyPrivCtrl(PrivCtrl privCtrl) { User user = SessionUtil.getCurrentUser(); if (user == null) { return false; } for (PrivCtrlType privCtrlType : privCtrl.value()) { if (privCtrlType.toString().equals(user.getType())) { return true; } } return false; } /** 登录重定向 */ private void loginRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException { request.getSession().setAttribute("request", RequestFactory.createReuqest(request)); response.setStatus(302); response.addHeader("Location", request.getContextPath() + "/user/login"); response.flushBuffer(); } }
权限验证不通过时保存请求信息并跳转到登录页面进行登录:
package com.liyh.controller; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import com.liyh.annotation.PrivCtrl; import com.liyh.domain.User; import com.liyh.domain.utils.Request; import com.liyh.enumeration.PrivCtrlType; import com.liyh.service.UserService; import com.liyh.utils.HttpClientUtil; import com.liyh.utils.SessionUtil; import com.liyh.utils.StringUtil; @Controller @RequestMapping("/user") public class UserController { @Resource private UserService userService; @RequestMapping(value="/login", method = RequestMethod.GET) public ModelAndView login(Map<String, Object> model, HttpServletRequest request) { HttpSession session = request.getSession(); Request preRequest = (Request) session.getAttribute("request"); if (preRequest != null) { if (preRequest.isSend()) { session.removeAttribute("request"); } else { preRequest.setSend(true); } } return new ModelAndView("user/login"); } @RequestMapping(value="/login", method = RequestMethod.POST) public String login(String username, String password, Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception{ User user = userService.findByUsername(username); if (user == null || !StringUtil.equals(user.getPassword(), password)) { model.put("rs", "fail"); model.put("msg", "登录失败"); model.put("username", username); return "user/login"; } SessionUtil.login(user); HttpSession session = request.getSes 9802 sion(); Request preRequest = (Request) session.getAttribute("request"); if (preRequest != null) { session.removeAttribute("request"); user = (User) session.getAttribute("User"); HttpClientUtil.send(response, preRequest); return null; } return "redirect:/"; } @PrivCtrl(PrivCtrlType.MEMBER) @RequestMapping(value="/login_success", method = RequestMethod.GET) public ModelAndView login_success(Map<String, Object> model, HttpServletRequest request) { return new ModelAndView("user/login_success"); } }
登录过后通过自制的Http客户端工具跳转到保存的请求页面:
package com.liyh.utils; import java.io.IOException; import java.io.PrintWriter; import java.util.Map; import javax.servlet.http.HttpServletResponse; import com.liyh.domain.utils.Request; public class HttpClientUtil { public static void send(HttpServletResponse response, Request request) throws IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); out.println("<HTML>"); out.println(" <HEAD><TITLE>sender</TITLE></HEAD>"); out.println(" <BODY>"); out.println("<form name=\"submitForm\" action=\"" + request.getUrl() + "\" method=\"" + request.getMethod() +"\">"); Map<String, String[]> params = request.getParameterMap(); for (String key : params.keySet()) { String[] values = params.get(key); for (String value : values) { out.println("<input type=\"hidden\" name=\"" + key + "\" value=\"" + value + "\"/>"); } } out.println("</from>"); out.println("<script>window.document.submitForm.submit();</script> "); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); } }
总结:
存在问题:Ajax请求的接口没有做额外处理,暂时还没有完善
解决方案:拦截器中判断是否是请求接口,如果是请求接口,则返回权限不足,需要封装Ajax请求方法,未登录时跳转到登录页面并记录当前URL
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统