概述
一 首先,获取spring security的当前用户:
Spring security获取当前用户
http://blog.csdn.net/tomcat_2014/article/details/50725723
.Java代码中使用
但我在实际运用中发现获得的Authentication为null。仔细看了下源代码发现,如果想用上面的代码获得当前用户,必须在spring
security过滤器执行中执行,否则在过滤链执行完时org.springframework.security.web.context.SecurityContextPersistenceFilter类会
调用SecurityContextHolder.clearContext();而把SecurityContextHolder清空,所以会得到null。 经过spring security认证后,
security会把一个SecurityContextImpl对象存储到session中,此对象中有当前用户的各种资料
二 然后,需要在Controller层建立切面拦截,参考:
使用Spring的注解方式实现AOP
http://blog.csdn.net/a352193394/article/details/7345860
spring对AOP的实现提供了很好的支持。下面我们就使用Spring的注解来完成AOP做一个例子。
首先,为了使用Spring的AOP注解功能,必须导入如下几个包。aspectjrt.jar,aspectjweaver.jar,cglib-nodep.jar.
然后我们写一个接口
和一个接口实现类
下面使用Spring注解方式对这个Bean进行方法拦截
这句话是方法切入点,execution为执行的意思,*代表任意返回值,然后是包名,.*意思是包下面的所有子包。(..)代
表各种方法.
然后下面的注解就比较简单了,就是在使用方法前和中,还有环绕拦截/
然后在Spring的配置文件中继续配置Bean,需要打开AOP命名空间
然后建立一个Junit测试
测试结果为
注意:
1.本博客中的 && args(name),我测下来这个before只能拦截到有一个参数的函数,如果要拦截所有签名的函数,则
// @Before("anyMethod()")
// public void doAccessCheck(){
// System.out.println("前置通知");
// }
2.本案采用spring aop而不是spring mvc拦截器,这之间的区别,在本博客底部转载
3.另有一篇参考博客:spring boot 使用spring AOP实现拦截器
http://blog.csdn.net/clementad/article/details/52035199,其中的
/**
* 定义拦截规则:拦截com.xjj.web.controller包下面的所有类中,有@RequestMapping注解的方法。
*/
@Pointcut("execution(* com.xjj.web.controller..*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void controllerMethodPointcut(){}
4.另有一篇博客,解释了spring mvc中使用aop失效的问题: SpringMVC中使用aop注解无效的问题
先备案:http://blog.csdn.net/u010483289/article/details/52725796
三 最后,有两个小问题:
1.业务要求,不同的Controller对应于不同的模块,这就要求在切面中跟踪是调用哪个类;
2.有些请求返回页面,有些请求返回对象,这就要求在切面中跟踪被切方法的返回类型。
参考:http://blog.csdn.net/meiyang1990/article/details/50562046 (ProceedingJoinPoint获取当前方法)
aspectJ切面通过ProceedingJoinPoint想要获取当前执行的方法:
错误方法:
Signature s = pjp.getSignature();
MethodSignature ms = (MethodSignature)s;
Method m = ms.getMethod();
这种方式获取到的方法是接口的方法而不是具体的实现类的方法,因此是错误的。
正确方法:
Signature sig = pjp.getSignature();
MethodSignature msig = null;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
msig = (MethodSignature) sig;
Object target = pjp.getTarget();
Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
唉,就因为这个摔了好大一跤
由于我这边是基于类而不是接口的,所以不考虑其中的正确方法,直接使用:
获取类:
pjp.getTarget().getClass()
获取返回类型
Class returnType = ((MethodSignature) pjp.getSignature()).getReturnType();
if(returnType.equals(String.class)) {
object = "common/noauth";
} else {
object = Result.genFail("没有权限");
}
切面图:
xxxController——xxx业务模块
xxxControler下属restful接口函数 xxdeletexx,xxsavexx函数,专门定义两个切面来拦截删除操作和更新操作,所以这就对代码命名有所要求
@Pointcut("execution(* com.ilex.jiutou.web..*delete*(..))")
private void deleteMethod(){}//定义一个切入点
@Pointcut("execution(* com.ilex.jiutou.web..*save*(..)) || execution(* com.ilex.jiutou.web..*update*(..))")
private void updateMethod(){}//定义一个切入点
我这边就是更新操作的命名没统一,有save和update两种,所以以 || 来建立或逻辑,(这里用 or 我测下来不行,只能截到 *save*的函数
以这种方式来控制在一个业务模块(xxxController)中不同的读写、删除权限。
完。
两个疑问:
@EnableAspectJAutoProxy我没加
spring.aop.proxy-target-class=true我没加
附件:spring aop与spring mvc拦截器的区别
http://www.lai18.com/content/2471799.html
谈谈spring中的拦截器interceptor
谈谈spring中的拦截器
在web开发中,拦截器是经常用到的功能。它可以帮我们验证是否登陆、预先设置数据以及统计方法的执行效率等等。今天就来详细的谈一下spring中的拦截器。spring中拦截器主要分两种,一个是HandlerInterceptor,一个是MethodInterceptor。一,HandlerInterceptor拦截器
HandlerInterceptor是springMVC项目中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行。实现一个HandlerInterceptor拦截器可以直接实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。这两种方法殊途同归,其实HandlerInterceptorAdapter也就是声明了HandlerInterceptor接口中所有方法的默认实现,而我们在继承他之后只需要重写必要的方法。下面就是HandlerInterceptorAdapter的代码,可以看到一个方法只是默认返回true,另外两个是空方法:- public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
- /**
- * This implementation always returns <code>true</code>.
- */
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- return true;
- }
- /**
- * This implementation is empty.
- */
- public void postHandle(
- HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
- throws Exception {
- }
- /**
- * This implementation is empty.
- */
- public void afterCompletion(
- HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception {
- }
- }
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- HttpServletRequest processedRequest = request;
- HandlerExecutionChain mappedHandler = null;
- int interceptorIndex = -1;
- try {
- ModelAndView mv;
- boolean errorView = false;
- try {
- processedRequest = checkMultipart(request);
- // Determine handler for the current request.
- mappedHandler = getHandler(processedRequest, false);
- if (mappedHandler == null || mappedHandler.getHandler() == null) {
- noHandlerFound(processedRequest, response);
- return;
- }
- // Determine handler adapter for the current request.
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- // Process last-modified header, if supported by the handler.
- String method = request.getMethod();
- boolean isGet = "GET".equals(method);
- if (isGet || "HEAD".equals(method)) {
- long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
- if (logger.isDebugEnabled()) {
- String requestUri = urlPathHelper.getRequestUri(request);
- logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
- }
- if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
- return;
- }
- }
- // Apply preHandle methods of registered interceptors.
- HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
- if (interceptors != null) {
- for (int i = 0; i < interceptors.length; i++) {
- HandlerInterceptor interceptor = interceptors[i];
- if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
- return;
- }
- interceptorIndex = i;
- }
- }
- // Actually invoke the handler.
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- // Do we need view name translation?
- if (mv != null && !mv.hasView()) {
- mv.setViewName(getDefaultViewName(request));
- }
- // Apply postHandle methods of registered interceptors.
- if (interceptors != null) {
- for (int i = interceptors.length - 1; i >= 0; i--) {
- HandlerInterceptor interceptor = interceptors[i];
- interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
- }
- }
- }
- catch (ModelAndViewDefiningException ex) {
- logger.debug("ModelAndViewDefiningException encountered", ex);
- mv = ex.getModelAndView();
- }
- catch (Exception ex) {
- Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
- mv = processHandlerException(processedRequest, response, handler, ex);
- errorView = (mv != null);
- }
- // Did the handler return a view to render?
- if (mv != null && !mv.wasCleared()) {
- render(mv, processedRequest, response);
- if (errorView) {
- WebUtils.clearErrorRequestAttributes(request);
- }
- }
- else {
- if (logger.isDebugEnabled()) {
- logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
- "': assuming HandlerAdapter completed request handling");
- }
- }
- // Trigger after-completion for successful outcome.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
- }
- catch (Exception ex) {
- // Trigger after-completion for thrown exception.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
- throw ex;
- }
- catch (Error err) {
- ServletException ex = new NestedServletException("Handler processing failed", err);
- // Trigger after-completion for thrown exception.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
- throw ex;
- }
- finally {
- // Clean up any resources used by a multipart request.
- if (processedRequest != request) {
- cleanupMultipart(processedRequest);
- }
- }
- }
代码有点长,但是它封装了springMVC处理请求的整个过程。首先根据请求找到对应的HandlerExecutionChain,它包含了处理请求的handler和所有的HandlerInterceptor拦截器;然后在调用hander之前分别调用每个HandlerInterceptor拦截器的preHandle方法,若有一个拦截器返回false,则会调用triggerAfterCompletion方法,并且立即返回不再往下执行;若所有的拦截器全部返回true并且没有出现异常,则调用handler返回ModelAndView对象;再然后分别调用每个拦截器的postHandle方法;最后,即使是之前的步骤抛出了异常,也会执行triggerAfterCompletion方法。关于拦截器的处理到此为止,接下来看看triggerAfterCompletion做了什么
- private void triggerAfterCompletion(HandlerExecutionChain mappedHandler,
- int interceptorIndex,
- HttpServletRequest request,
- HttpServletResponse response,
- Exception ex) throws Exception {
- // Apply afterCompletion methods of registered interceptors.
- if (mappedHandler != null) {
- HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
- if (interceptors != null) {
- for (int i = interceptorIndex; i >= 0; i--) {
- HandlerInterceptor interceptor = interceptors[i];
- try {
- interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex);
- }
- catch (Throwable ex2) {
- logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
- }
- }
- }
- }
- }
根据以上的代码,分析一下不同拦截器及其方法的执行顺序。假设有5个拦截器编号分别为12345,若一切正常则方法的执行顺序是12345的preHandle,54321的postHandle,54321的afterCompletion。若编号3的拦截器的preHandle方法返回false或者抛出了异常,接下来会执行的是21的afterCompletion方法。这里要注意的地方是,我们在写一个拦截器的时候要谨慎的处理preHandle中的异常,因为这里一旦有异常抛出就不会再受到这个拦截器的控制。12345的preHandle的方法执行过之后,若handler出现了异常或者某个拦截器的postHandle方法出现了异常,则接下来都会执行54321的afterCompletion方法,因为只要12345的preHandle方法执行完,当前拦截器的拦截器就会记录成编号5的拦截器,而afterCompletion总是从当前的拦截器逆向的向前执行。
另外,实现HandlerInterceptor拦截器还有一个方法,就是实现WebRequestInterceptor接口。其实它和刚才的两种方法也是殊途同归,最终还是被spring适配成HandlerInterceptor。有一点不同,它的preHandle方法最终只会返回true。
二,MethodInterceptor拦截器
MethodInterceptor是AOP项目中的拦截器,它拦截的目标是方法,即使不是controller中的方法。实现MethodInterceptor拦截器大致也分为两种,一种是实现MethodInterceptor接口,另一种利用AspectJ的注解或配置。下面是第一种方法的示例
- public class MethodInvokeInterceptor implements MethodInterceptor {
- @Override
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- System.out.println("before method invoke");
- Object object = methodInvocation.proceed();
- System.out.println("after method invoke");
- return object;
- }
- }
- @Component
- @Aspect
- public class AutoAspectJInterceptor {
- @Around("execution (* com.test.controller..*.*(..))")
- public Object around(ProceedingJoinPoint point) throws Throwable{
- System.out.println("AutoAspectJInterceptor begin around");
- Object object = point.proceed();
- System.out.println("AutoAspectJInterceptor end around");
- return object;
- }
- }
- @Component
- public class AspectJInterceptor {
- public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
- System.out.println("AspectJInterceptor around before");
- Object object = proceedingJoinPoint.proceed();
- System.out.println("AspectJInterceptor around after");
- return object;
- }
- }
- <!-- 自定义拦截器 ,先过mvc:interceptors-->
- <bean id="methodInvokeInterceptor" class="com.test.interceptor.MethodInvokeInterceptor"/>
- <bean id="aspectInterceptor" class="com.test.interceptor.AspectJInterceptor"/>
- <aop:config>
- <!--切入点,controlller -->
- <aop:pointcut id="pointcut_test" expression="execution(* com.test.controller..*.*(..))" />
- <!--在该切入点使用自定义拦截器 ,按照先后顺序执行 -->
- <aop:advisor pointcut-ref="pointcut_test" advice-ref="methodInvokeInterceptor" />
- <aop:aspect ref="aspectInterceptor">
- <aop:around method="around" pointcut="execution(* com.test.controller..*.*(..))"/>
- </aop:aspect>
- </aop:config>
- <!-- 自动扫描使用了aspectj注解的类 -->
- <aop:aspectj-autoproxy/>
通过上面的配置三个MethodInterceptor就能正常工作了。其实,这两种实现方式。。。。。最终。。。。。。没错,还是殊途同归。aspectj的拦截器会被解析成AOP中的advice,最终被适配成MethodInterceptor,详细的过程请参考springAOP的实现。
三,谈一谈区别
上面的两种拦截器都能起到拦截的效果,但是他们拦截的目标不一样,实现的机制不同,所以有的时候适用不同的场景。HandlerInterceptoer拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。当你需要统计请求的响应时间时MethodInterceptor将不太容易做到,因为它可能跨越很多方法或者只涉及到已经定义好的方法中一部分代码。MethodInterceptor利用的是AOP的实现机制,在本文中只说明了使用方式,关于原理和机制方面介绍的比较少,因为要说清楚这些需要讲出AOP的相当一部分内容。在对一些普通的方法上的拦截HandlerInterceptoer就无能为力了,这时候只能利用AOP的MethodInterceptor。另外,还有一个跟拦截器类似的东西----Filter。Filter是Servlet规范规定的,不属于spring框架,也是用于请求的拦截。但是它适合更粗粒度的拦截,在请求前后做一些编解码处理、日志记录等。而拦截器则可以提供更细粒度的,更加灵活的,针对某些请求、某些方法的组合的解决方案。
另外的另外,用过人人网的ROSE框架的人都会非常喜欢它的拦截器功能。因为它实现了全注解的方式,只要在类的名字上加上拦截器的注解即表示这是一个拦截器。而使用这个拦截器的方法或者controller也只需在方法或controller的上面加上这个拦截器的注解。其实这是一个关注点的转变,spring的切面控制在配置文件中,配置文件关注哪些地方需要拦截。而在ROSE中,则是在需要拦截的地方关注我要被谁拦截。
以上纯属个人观点,欢迎交流!
最后
以上就是个性台灯为你收集整理的基于spring security及spring aop的权限控制的全部内容,希望文章能够帮你解决基于spring security及spring aop的权限控制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复