概述
一、定义自定义注解
/**
* 自定义注解
* 如果Controller 有该标记,那么这个Controller下面所有的方法都会被过滤器进行验证
* 如果Controller 没有有该标记,但Controller中的某个方法拥有该标记,那么这个方法将被过滤器验证(其他没有被标记的不会被验证)
* @author Chen,Shunhua
* @date 2017年9月21日 下午3:09:11
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE}) //该注解修饰类中的方法,准许controller和子方法添加本注解
//@Target(ElementType.METHOD) //该注解修饰类中的方法,只准许子方法添加本注解
@Order(Ordered.HIGHEST_PRECEDENCE) //最高优先级
public @interface RequestLimit {
/**
* controller对应的访问路径
* 功能集的路径
*/
String fun_assembly_url();
/**
* 功能点的路径
*/
String function_name();
/**
* 功能点名称
*/
String name();
/**
* 是否需要进行权限验证
*/
boolean is_validate();
/**
* 功能点或者功能集描述
*/
String desc();
}
二、在需要进行权限验证的controller类的方法中添加自定义注解
/**
* 设备接入方式管理
* 如果AccessModeController类名上不添加@RequestLimit注解,则需要在每个method方法中添加功能集的路径
* @author Chen,Shunhua
* @date 2017年4月17日 下午3:24:23
*/
@Controller
@RequestLimit(fun_assembly_url = "/manager/AccessMode", desc = "接入方式管理", is_validate = false, name = "mapping", function_name = "")
@RequestMapping("/manager/AccessMode")
public class AccessModeController {
static Logger logger = LogManager.getLogger(AccessModeController.class.getName());
@Autowired
private AccessModeService AccessModeService;
@Autowired
private BasePopedomService BasePopedomService; //菜单权限
private String page_path = "/pages/demo/AccessMode/"; //页面所在目录
/**
* 跳转到list页面
*/
@RequestLimit(fun_assembly_url = "", desc = "跳转到list页面", is_validate = false, name = "默认显示界面", function_name = "load")
@RequestMapping("/load")
public ModelAndView load(String menuPathName, HttpSession session, HttpServletRequest request,
HttpServletResponse response, ModelMap modelMap) throws IOException{
String function_name = request.getRequestURI();
String fun_function_name = function_name.substring(0, function_name.lastIndexOf("/"));
JSONArray basePopedomList = BasePopedomService.selectListByMenuUrl(request.getSession(), fun_function_name); //功能集对应的功能点列表
modelMap.put("button_list", basePopedomList);
modelMap.put("menuPathName", menuPathName);
return new ModelAndView(page_path + "list.jsp");
}
/**
* 查询列表
* @param typeName 类型名称
* @param typeCode 类型编码
* @param page 查询每页的条数
* @param rows 每页查询的条数
*/
@RequestLimit(fun_assembly_url = "", desc = "分页查询", is_validate = false, name = "查询列表", function_name = "list")
@RequestMapping("/list")
@ResponseBody
public PageInfo<AccessMode> list(int page, int rows, AccessMode record) throws IOException{
PageHelper.startPage(page, rows);
record.setIsDel(0); //查询未删除的
List<AccessMode> list = AccessModeService.selectListByCondition(record);
PageInfo<AccessMode> pg = new PageInfo<AccessMode>(list);
return pg;
}
/**
* 跳转到添加页面
*/
@RequestLimit(fun_assembly_url = "", desc = "跳转到添加页面", is_validate = true, name = "添加", function_name = "toAdd")
@RequestMapping("/toAdd")
public ModelAndView toAdd(){
return new ModelAndView(page_path + "add.jsp");
}
}
三、重新定义拦截器,在拦截器中队controller的权限进行验证
/**
* 自定义拦截器
* @author Chen,Shunhua
* @date 2017年6月19日 上午10:27:15
*/
@Controller
public class AuthenticationInterceptor implements HandlerInterceptor {
private String page_path = "/pages/error/"; //页面所在目录
//@Resource
@Autowired
private BasePopedomService BasePopedomService; //菜单权限
/**
* preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,SpringMVC中的Interceptor拦截器是链式的,可以同时存在
* 多个Interceptor,然后SpringMVC会根据声明的前后顺序一个接一个的执行,而且所有的Interceptor中的preHandle方法都会在
* Controller方法调用之前调用。SpringMVC的这种Interceptor链式结构也是可以进行中断的,这种中断方式是令preHandle的返
* 回值为false,当preHandle的返回值为false的时候整个请求就结束了。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod myHandlerMethod = (HandlerMethod) handler;
Method method = myHandlerMethod.getMethod();
@SuppressWarnings("unchecked")
Class<AccessModeController> type = (Class<AccessModeController>) myHandlerMethod.getBeanType(); //对应的controller方法
RequestLimit requestLimit = method.getAnnotation(RequestLimit.class); //功能点对应的请求方法
if (requestLimit == null) {
// 如果注解为null, 说明不需要拦截, 直接放过
return true;
}
if (requestLimit.is_validate()) {//需要进行权限判断
//项目访问路径
String basePath = request.getScheme()+"://"+request.getServerName();
if(request.getServerPort()!=80){
basePath+=":"+request.getServerPort();
}
basePath += ((HttpServletRequest) request).getContextPath() +"/";
// 如果权限配置不为空, 则取出配置值
String action = requestLimit.function_name(); //功能点路径
String fun_url = requestLimit.fun_assembly_url(); //controller方法路径
if(StringUtils.isBlank(fun_url)){//功能点对应注解上的功能集路径为空
RequestLimit parent = type.getAnnotation(RequestLimit.class); //controller的注解
fun_url = parent.fun_assembly_url(); //controller方法中注解上的功能集的路径
}
HttpSession session = request.getSession();
if (BasePopedomService == null) {//解决service为null无法注入问题
System.out.println("BasePopedomService is null!!!");
BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
BasePopedomService = (BasePopedomService) factory.getBean("BasePopedomService");
}
boolean is_validate = false; //是否有权限
JSONArray basePopedomList = BasePopedomService.selectListByMenuUrl(session, fun_url); //菜单对应的按钮列表
if(null != basePopedomList && basePopedomList.size() > 0){
action = action.toLowerCase(); //变成小写
for(int m=0; m<basePopedomList.size(); m++){
JSONObject son_temp = JSONObject.fromObject(basePopedomList.get(m));//获取数组第一个json的字符串 并转化成json对象
String son_mod_code = son_temp.getString("function_name"); //功能点方法
son_mod_code = son_mod_code.toLowerCase();
if(action.contains(son_mod_code)){//有权限
is_validate = true;
break;
}
}
}
if(is_validate){//按钮具有权限
return true;
}else{//按钮没有权限
response.setContentType("text/html");
String noPermissionsPage = basePath + "manager/login/error?msg=MSG_NO_PERMISSIONS"; //返回登陆首页的方法
response.sendRedirect(noPermissionsPage);
return false;
}
}
}
return true;// 只有返回true才会继续向下执行,返回false取消当前请求
}
/**
* 这个方法只会在当前这个Interceptor的preHandle方法返回值为true的时候才会执行。postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之
* 后,也就是在Controller的方法调用之后执行,但是它会在DispatcherServlet进行视图的渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操
* 作。这个方法的链式结构跟正常访问的方向是相反的,也就是说先声明的Interceptor拦截器该方法反而会后调用,这跟Struts2里面的拦截器的执行过程有点像,
* 只是Struts2里面的intercept方法中要手动的调用ActionInvocation的invoke方法,Struts2中调用ActionInvocation的invoke方法就是调用下一个Interceptor
* 或者是调用action,然后要在Interceptor之前调用的内容都写在调用invoke之前,要在Interceptor之后调用的内容都写在调用invoke方法之后。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// System.out.println(">>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
String url = request.getRequestURI();
if(response.getStatus()==500){
//modelAndView.addObject("msg", Constants.MSG_500);
String ticket = request.getQueryString(); //返回的ticket
if(StringUtils.isNotBlank(ticket)){//有tikect,说明是该url不准许登陆
modelAndView.setViewName(page_path + "login_no_permissions.jsp");
}else{//请求出错
modelAndView.setViewName(page_path + "500.jsp");
}
//modelAndView.addObject("msg", Constants.MSG_500);
}else if(response.getStatus()==404 && (url.contains("plugins") && url.contains(".map"))){//IE8下报找不到.map错误
//modelAndView.addObject("msg", Constants.MSG_404);
modelAndView.setViewName(page_path + "404.jsp");
}
//modelAndView.setViewName(page_path + "/pages/error.jsp");
}
/**
* 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行,
* 这个方法的主要作用是用于清理资源的,当然这个方法也只能在当前这个Interceptor的preHandle方法的返回值为true时才会执行。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// System.out.println(">>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
}
}
四、在spring boot启动类中引入自定义的拦截器
public class Application extends WebMvcConfigurerAdapter{
/**
* 拦截器配置
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 多个拦截器组成一个拦截器链
// addPathPatterns 用于添加拦截规则
// excludePathPatterns 用户排除拦截
registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
最后
以上就是安静大船为你收集整理的spring boot 自定义注解实现权限验证的全部内容,希望文章能够帮你解决spring boot 自定义注解实现权限验证所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复