注解類:
@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>