1. 程式人生 > >SpringMVC學習系列(9) 之 實現註解式許可權驗證

SpringMVC學習系列(9) 之 實現註解式許可權驗證

對大部分系統來說都需要許可權管理來決定不同使用者可以看到哪些內容,那麼如何在Spring MVC中實現許可權驗證呢?當然我們可以繼續使用servlet中的過濾器Filter來實現。但藉助於Spring MVC中的action攔截器我們可以實現註解式的許可權驗證。

一.首先介紹一下action攔截器:

HandlerInterceptor是Spring MVC為我們提供的攔截器介面,來讓我們實現自己的處理邏輯,HandlerInterceptor 的內容如下:

public interface HandlerInterceptor {  
    boolean preHandle(  
            HttpServletRequest request, HttpServletResponse response,   
            Object handler)   
            
throws Exception; void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception; }

可以看到介面有3個方法,其含義如下:

preHandle:在執行action裡面的處理邏輯之前執行,它返回的是boolean,這裡如果我們返回true在接著執行postHandle和afterCompletion,如果我們返回false則中斷執行。

postHandle:在執行action裡面的邏輯後返回檢視之前執行。

afterCompletion:在action返回檢視後執行。

HandlerInterceptorAdapter介面卡是Spring MVC為了方便我們使用HandlerInterceptor而對HandlerInterceptor 的預設實現,裡面的3個方法沒有做任何處理,在preHandle方法直接返回true,這樣我們繼承HandlerInterceptorAdapter後只需要實現3個方法中我們需要的方法即可,而不像繼承HandlerInterceptor一樣不管是否需要3個方法都要實現。

當然藉助於HandlerInterceptor我們可以實現很多其它功能,比如日誌記錄、請求處理時間分析等,許可權驗證只是其中之一。

二.下面我們就來一步一步來完成註解式許可權驗證的功能。

首先新增一個賬戶的Controller和登入的Action及檢視來模擬在沒有許可權時跳轉到登陸頁面,內容分別如下:

com.demo.web.controllers包中的AccountController.java:

package com.demo.web.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value = "/account")
public class AccountController {
    
    @RequestMapping(value="/login", method = {RequestMethod.GET})
    public String login(){
        
        return "login";
    }
    
}

views資料夾下的檢視login.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    這裡是登入介面
</body>
</html>

新建包com.demo.web.auth,新增自定義註解AuthPassport,內容如下:

package com.demo.web.auth;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthPassport {
    boolean validate() default true;
}

新增自己的攔截器實現AuthInterceptor繼承於HandlerInterceptorAdapter,內容如下:

package com.demo.web.auth;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class AuthInterceptor extends HandlerInterceptorAdapter {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
        if(handler.getClass().isAssignableFrom(HandlerMethod.class)){
            AuthPassport authPassport = ((HandlerMethod) handler).getMethodAnnotation(AuthPassport.class);
            
            //沒有宣告需要許可權,或者宣告不驗證許可權
                if(authPassport == null || authPassport.validate() == false)
                return true;
            else{                
                //在這裡實現自己的許可權驗證邏輯
                if(false)//如果驗證成功返回true(這裡直接寫false來模擬驗證失敗的處理)
                    return true;
                else//如果驗證失敗
                {
                    //返回到登入介面
                    response.sendRedirect("account/login");
                    return false;
                }       
            }
        }
        else
            return true;   
     }
}

配置專案的springservlet-config.xml新增如下內容:

<mvc:interceptors>  
    <!-- 國際化操作攔截器 如果採用基於(請求/Session/Cookie)則必需配置 --> 
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />  
    <!-- 如果不定義 mvc:mapping path 將攔截所有的URL請求 -->
    <bean class="com.demo.web.auth.AuthInterceptor"></bean>
</mvc:interceptors>

這樣在執行每個action方法是都會呼叫AuthInterceptor處理,當判斷action上有我們定義AuthPassport註解時就會執行裡面的許可權驗證邏輯。

執行專案:

1

可以看到執行了我們在springservlet-config.xml定義的HelloworldController的index方法。

<!-- 如果當前請求為“/”時,則轉發到“/helloworld/index" -->
<mvc:view-controller path="/" view-name="forward:/helloworld/index"/>

下面我們在HelloworldController的index方法上加上自定義註解AuthPassport:

@AuthPassport
@RequestMapping(value={"/index","/hello"})
public ModelAndView index(){
    
    ModelAndView modelAndView = new ModelAndView();  
    modelAndView.addObject("message", "Hello World!");  
    modelAndView.setViewName("index");  
    return modelAndView;
}

重新執行專案:

2

可以看到正確執行了許可權判斷邏輯,這樣我們只需要在我們在需要許可權驗證的action上加上這個註解就可以實現許可權控制功能了。

註解式許可權驗證的內容到此結束。

注: 之前沒注意前11篇的示例程式碼,不知道為什麼當時打包上傳上去的是沒有.project專案檔案的,導致下載後不能直接匯入eclipse執行,虛擬機器又 被我刪掉了,這些示例程式碼也沒有備份,但是程式碼檔案還在的,所以可以新建一個Dynamic Web Project把對應的配置檔案和controller還有view匯入就可以了,給大家造成的不便說聲抱歉。