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