天天看點

springmvc自定義注解攔截器方式實作注解功能攔截器的配置

注解類:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface TokenRequiresRoles {
	
    /**
     * A single String role name or multiple comma-delimitted role names required in order for the method
     * invocation to be allowed.
     */
    String[] value();

}
           

使用攔截器的方式:

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.google.gson.Gson;
import com.heiman.smarthome.po.custom.Config;
import com.heiman.smarthome.po.custom.Error;
import com.heiman.smarthome.utils.JWTEncodeAndDecode;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.SignatureException;

/**
 * @Description : 從token中擷取使用者擁有的角色,和連結需要的角色作比較, 如果缺少角色,則禁止通路該連結,并傳回錯誤碼和錯誤資訊
 */
public class TokenAnnotationInterceptor extends HandlerInterceptorAdapter {

	@Autowired
	private Config config;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// TODO Auto-generated method stub
		// 檢查使用者是否擁有權限
		return checkRole(request, response, handler);
	}

	/**
	 * 檢查被注解的類是否擁有權限
	 * 
	 * @param request
	 * @param response
	 * @param handler
	 * @return
	 */
	public boolean checkRole(HttpServletRequest request, HttpServletResponse response, Object handler) {

		String header = request.getHeader("Access-Token");
		Gson gson = new Gson();

		if (handler instanceof HandlerMethod) {
			HandlerMethod hm = (HandlerMethod) handler;
			Class<?> clazz = hm.getBeanType();
			Method m = hm.getMethod();
			try {
				if (clazz != null && m != null) {
					// 檢查類和方法是否有注解
					boolean isClzAnnotation = clazz.isAnnotationPresent(TokenRequiresRoles.class);
					boolean isMethondAnnotation = m.isAnnotationPresent(TokenRequiresRoles.class);
					TokenRequiresRoles rc = null;

					// 如果方法和類聲明中同時存在這個注解,那麼方法中的會覆寫類中的設定。
					if (isMethondAnnotation) {
						rc = m.getAnnotation(TokenRequiresRoles.class);
					} else if (isClzAnnotation) {
						rc = clazz.getAnnotation(TokenRequiresRoles.class);
					}

					// 注解中需要的角色
					String[] value = rc.value();
					List<String> requireRole = new ArrayList<String>();
					Collections.addAll(requireRole, value);

					// 解碼token擷取角色
					Claims decode = JWTEncodeAndDecode.decode(header);
					String[] roles = JWTEncodeAndDecode.getRoles(decode);
					List<String> tokenRole = new ArrayList<String>();
					Collections.addAll(tokenRole, roles);

					// 進行角色通路的權限控制,隻有目前使用者是需要的角色才予以通路。
					boolean isEquals = tokenRole.containsAll(requireRole);

					if (!isEquals) {
						// 未授權通路
						Error error = new Error(434627, "Unauthorized access");
						response.getWriter().write(gson.toJson(error));
						return false;
					}
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				if (config.printError())
					e.printStackTrace();
			}
		}

		return true;
	}

}
           

springmvc中配置攔截器:

<!-- 攔截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<!-- 比對的是url路徑, 如果不配置或/**,将攔截所有的Controller -->
			<mvc:mapping path="/v1/**" />
			<mvc:mapping path="/v2/**" />
			<!-- 攔截器類 -->
			<bean
				class="com.heiman.smarthome.spring.annotation.TokenAnnotationInterceptor"></bean>
		</mvc:interceptor>
		<!-- 當設定多個攔截器時,先按順序調用preHandle方法,然後逆序調用每個攔截器的postHandle和afterCompletion方法 -->
	</mvc:interceptors>
           

繼續閱讀