java设置校验功能_Spring AOP 实现功能权限校验功能

实现功能权限校验的功能有多种方法,其一使用拦截器拦截请求,其二是使用AOP抛异常。

首先用拦截器实现未登录时跳转到登录界面的功能。注意这里没有使用AOP切入,而是用拦截器拦截,因为AOP一般切入的是service层方法,而拦截器是拦截控制器层的请求,它本身也是一个处理器,可以直接中断请求的传递并返回视图,而AOP则不可以。

1.使用拦截器实现未登录时跳转到登录界面的功能

1.1 拦截器SecurityInterceptor

package com.jykj.demo.filter;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;

import com.jykj.demo.util.Helper;

import com.jykj.demo.util.Result;

public class SecurityInterceptor implements HandlerInterceptor{

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

System.out.println("SecurityInterceptor:"+request.getContextPath()+","+request.getRequestURI()+","+request.getMethod());

HttpSession session = request.getSession();

if (session.getAttribute(Helper.SESSION_USER) == null) {

System.out.println("AuthorizationException:未登录!"+request.getMethod());

if("POST".equalsIgnoreCase(request.getMethod())){

response.setContentType("text/html; charset=utf-8");

PrintWriter out = response.getWriter();

out.write(JSON.toJSONString(new Result(false,"未登录!")));

out.flush();

out.close();

}else{

response.sendRedirect(request.getContextPath()+"/login");

}

return false;

} else {

return true;

}

}

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

// TODO Auto-generated method stub

}

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

throws Exception {

// TODO Auto-generated method stub

}

}

1.2.spring-mvc.xml(拦截器配置部分)

这里需要特别说明:拦截器拦截的路径最好是带有后缀名的,否则一些静态的资源文件不好控制,也就是说请求最好有一个统一的格式如 .do 等等,这样匹配与过滤速度会非常快。如果不这样,例如 用 /** 来拦截所有的请求,则页面渲染速度会非常慢,因为资源文件也被拦截了。

2.使用AOP实现功能权限校验

对于功能权限校验也可以类似地用拦截器来实现,只不过会拦截所有的请求,对不需要权限校验的请求没有很好的过滤功能,所以采用AOP指定拦截需要校验的方法的方式来实现之。

2.1 切面类 PermissionAspect

package com.jykj.demo.filter;

import java.io.IOException;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.beans.factory.annotation.Autowired;

import com.jykj.demo.annotation.ValidatePermission;

import com.jykj.demo.exception.AccessDeniedException;

import com.jykj.demo.service.SysUserRolePermService;

/**

* 事件日志 切面,凡是带有 @ValidatePermission 以及@ResponseBody注解 控制器 都要进行 功能权限检查,

* 若无权限,则抛出AccessDeniedException 异常,该异常将请求转发至一个控制器,然后将异常结果返回

* @author Administrator

*

*/

public class PermissionAspect {

@Autowired

SysUserRolePermService sysUserRolePermService;

public void doBefore(JoinPoint jp) throws IOException{

System.out.println(

"log PermissionAspect Before method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());

Method soruceMethod = getSourceMethod(jp);

if(soruceMethod!=null){

ValidatePermission oper = soruceMethod.getAnnotation(ValidatePermission.class);

if (oper != null) {

int fIdx = oper.idx();

Object[] args = jp.getArgs();

if (fIdx>= 0 &&fIdx

int functionId = (Integer) args[fIdx];

String rs = sysUserRolePermService.permissionValidate(functionId);

System.out.println("permissionValidate:"+rs);

if(rs.trim().isEmpty()){

return ;//正常

}

}

}

}

throw new AccessDeniedException("您无权操作!");

}

private Method getSourceMethod(JoinPoint jp){

Method proxyMethod = ((MethodSignature) jp.getSignature()).getMethod();

try {

return jp.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (SecurityException e) {

e.printStackTrace();

}

return null;

}

}

2.2自定义注解ValidatePermission

package com.jykj.demo.annotation;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

*@Descrption该注解是标签型注解,被此注解标注的方法需要进行权限校验

*/

@Target(value = ElementType.METHOD)

@Retention(value = RetentionPolicy.RUNTIME)

@Documented

public @interface ValidatePermission {

/**

*@Description功能Id的参数索引位置 默认为0,表示功能id在第一个参数的位置上,-1则表示未提供,无法进行校验

*/

int idx() default 0;

}

说明: AOP切入的是方法,不是某个控制器请求,所以不能直接返回视图来中断该方法的请求,但可以通过抛异常的方式达到中断方法执行的目的,所以在before通知中,如果通过验证直接return返回继续执行连接点方法,否则抛出一个自定义异常AccessDeniedException来中断连接点方法的执行。该异常的捕获可以通过系统的异常处理器(可以看做控制器)来捕获并跳转到一个视图或者一个请求。这样就达到拦截请求的目的。所以需要配置异常处理器。

2.3 spring-mvc.xml(异常处理器配置,以及aop配置)

forward:/accessDenied

expression="@annotation(com.jykj.demo.annotation.ValidatePermission)

and @annotation(org.springframework.web.bind.annotation.ResponseBody)

and execution(* com.jykj.demo.controller..*.*(..)) " />

2.5 异常处理器将请求转发到的控制器请求 forward:/accessDenied

@RequestMapping(value = "/accessDenied",produces = "text/html;charset=UTF-8")

@ResponseBody

public String accessDenied(){

return JSON.toJSONString(new Result(false,"您没有权限对此进行操作!"));

}

2.6 请求校验不通过时 由上述的控制器返回 结果本身

如下所示:

{"info":"您没有权限对此进行操作!","success":false}

1

2.7 功能校验service 示例

/**

* 校验当前用户在某个模块的某个功能的权限

*@param functionId

*@return 空字符串表示 有权限 ,否则是错误信息

*@throws Exception

*/

public String permissionValidate(int functionId){

Object o = request.getSession().getAttribute(Helper.SESSION_USER);

//if(o==null) throw new AuthorizationException();

SysUser loginUser= (SysUser)o;

if(loginUser.getUserid() == 1) return "";

try{

return mapper.permissionValidate(loginUser.getUserid(),functionId);

}catch(Exception ex){

ex.printStackTrace();

return "数据库操作出现异常!";

}

}

说明: 这里仅仅是对带有@ValidatePermission和@ResponseBody注解的controller包及其子包所有方法进行切入,这样肯定是不够通用的,应该是对带有@ValidatePermission的方法进行切入,在切面类中通过判断该方法是否有@ResponseBody注解来抛出不一样的异常,若带有@ResponseBody注解则抛出上述的异常返回json字符串,

否则,应该抛出另一个自定义异常然后将请求重定向到一个合法的视图如error.jsp .

通过客户端发送 /moduleAccess.do 请求,该请求对应的方法同时具有@ValidatePermission和@ResponseBody,并且有功能Id参数fid,这样AOP可以切入该方法,执行doBefore通知,通过功能参数fid,对它结合用户id进行权限校验,若校验通过直接返回,程序继续执行,否则抛出自定义异常AccessDeniedException,该异常由系统捕获(需要配置异常处理器)并发出请求 forward:/accessDenied ,然后对应的控制器 /accessDenied 处理该请求返回一个包含校验失败信息的json给客户端。这样发送 /moduleAccess.do 请求,如果校验失败,转发到了/accessDenied请求,否则正常执行。绕了这么一个大圈子才实现它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值