SpringMVC结合Shiro注解实现权限控制原理分析

        在之前项目中,整合过无数次的SSM,但都没有去仔细分析SpringMVC结合Shiro注解实现权限控制的具体流程,刚好今天处理系统的Ajax非法请求的异常信息处理,现将其执行流程以及原理记录如下:

1、启用Shiro注解
系统中如果需要使用Shiro的注解来控制方法级的权限,则需要做如下的配置:

    

	
	
		
	


	
	
		
	

配置中的AuthorizationAttributeSourceAdvisor切面类中创建了一个AOP配置类,该配置类专门处理Shiro权限注解的方法拦截(AopAllianceAnnotationsAuthorizingMethodInterceptor)。核心代码如下:

public AopAllianceAnnotationsAuthorizingMethodInterceptor() {
        List interceptors =
                new ArrayList(5);

        //use a Spring-specific Annotation resolver - Spring's AnnotationUtils is nicer than the
        //raw JDK resolution process.
        AnnotationResolver resolver = new SpringAnnotationResolver();
        //we can re-use the same resolver instance - it does not retain state:
        interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
        interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
        interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
        interceptors.add(new UserAnnotationMethodInterceptor(resolver));
        interceptors.add(new GuestAnnotationMethodInterceptor(resolver));

        setMethodInterceptors(interceptors);
    }

/**
     * Creates a Shiro {@link MethodInvocation MethodInvocation} instance and then immediately calls
     * {@link org.apache.shiro.authz.aop.AuthorizingMethodInterceptor#invoke super.invoke}.
     *
     * @param methodInvocation the AOP Alliance-specific methodInvocation instance.
     * @return the return value from invoking the method invocation.
     * @throws Throwable if the underlying AOP Alliance method invocation throws a Throwable.
     */
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);
        return super.invoke(mi);
    }

 

2、配置Shiro拦截器和SpringMVC的核心控制器


		shiroFilter
		org.springframework.web.filter.DelegatingFilterProxy
		true
		
			targetFilterLifecycle
			true
		
	
	
		shiroFilter
		/*
	
	
		dispatcherServlet
		org.springframework.web.servlet.DispatcherServlet
		
			contextConfigLocation
			classpath:spring/applicationContext-mvc.xml
		
	
	
		dispatcherServlet
		/
	

请求进入系统后,先执行Shiro的拦截器链AbstractShiroFilter,Shiro拦截器链执行完过后执行dispatcherServlet的方法。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);


				// 获取SpringMVC的Handler(RequestMappingHandlerAdapter)
				mappedHandler = getHandler(processedRequest);
				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()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
                // 执行Controller
                // 触发Shiro注解拦截器AuthorizingAnnotationMethodInterceptor
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(request, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
            // 出现认证异常UnauthorizedException,寻找异常控制器
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

3、编写异常处理Handler

/**
	 * @Description: 认证失败异常处理
	 * @return String
	 */
	@ExceptionHandler({ UnauthenticatedException.class, AuthenticationException.class })
	public String authenticationException(HttpServletRequest request, HttpServletResponse response)
	{
		if (isAjaxRequest(request))
		{
			AppResult appResult = AppResult.error("系统认证失败,拒绝访问!");
			ResponseUtil.renderJson(response, JSON.toJSONString(appResult));
			return null;
		}
		else
			return "error/401";
	}

	/**
	 * @Description: 授权失败异常处理
	 * @return String
	 */
	@ExceptionHandler({ UnauthorizedException.class, AuthorizationException.class })
	public String authorizationException(HttpServletRequest request, HttpServletResponse response)
	{
		if (isAjaxRequest(request))
		{
			AppResult appResult = AppResult.error("系统授权失败,拒绝访问!");
			ResponseUtil.renderJson(response, JSON.toJSONString(appResult));
			return null;
		}
		else
			return "error/401";
	}

	public static boolean isAjaxRequest(HttpServletRequest request)
	{
		String requestedWith = request.getHeader("x-requested-with");
		return StringUtils.isNotEmpty(requestedWith) && requestedWith.equalsIgnoreCase("XMLHttpRequest");
	}

 

格式有点乱,仅作为流程分析参考。

转载于:https://my.oschina.net/wuzb/blog/997646

你可能感兴趣的:(SpringMVC结合Shiro注解实现权限控制原理分析)