对于增删改接口,管理员权限能操作,用户权限不能操作.
1. 定义一个注解类
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RoleOfAdmin {
String value() default "admin";
}
2.重写BeanPostProcessor,在spring创建bean之后,在自建的容器中存储有自定义注解的bean信息
@Component
public class AuthorityControllerBeanProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
return o;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class clazz = bean.getClass();
Boolean isControllerAnnotationInClass = clazz.isAnnotationPresent(Controller.class) || clazz.isAnnotationPresent(RestController.class);
if (isControllerAnnotationInClass) {
// 如果这是一个 Controller Bean 的话
// 那么就读取所有方法的权限配置
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
for (Method method : methods) {
Boolean isAuthorityAnnotationInMethod = method.isAnnotationPresent(RoleOfAdmin.class);
if (isAuthorityAnnotationInMethod) {
// 如果有 @Authority 注解的话
// 则记录该注解中的内容
String target = bean.getClass().getName() + "." + method.getName();
RoleOfAdmin annotation = method.getAnnotation(RoleOfAdmin.class);
AuthorityAnnotationContainer.set(target,annotation);
}
}
return bean;
} else {
// 否则的话直接返回Bean
return bean;
}
}
}
3. 建的存储有自定义注解bean信息的容器
public class AuthorityAnnotationContainer {
public static ConcurrentHashMap<String,Object> ROLE_MAP =new ConcurrentHashMap<String,Object>() ;
public static void set(String target, RoleOfAdmin roleOfAdmin){
ROLE_MAP.put(target,roleOfAdmin);
}
public static void remove(String target){
ROLE_MAP.remove(target);
}
public static RoleOfAdmin get(String target){
RoleOfAdmin roleOfAdmin = (RoleOfAdmin) ROLE_MAP.get(target);
return roleOfAdmin;
}
}
4. 配置一个拦截器,用来获取controller里方法上的自定义注解. 如果有该注解,会从Threadlocal里拿到用户权限信息,这个用户权限信息是在这个拦截器之前的一个身份拦截器里获取到的,代码详见另一篇文章 文章地址
@Component
public class AuthorityInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 将handler强转为HandlerMethod, 前面已经证实这个handler就是HandlerMethod
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 从方法处理器中获取出要调用的方法
Method method = handlerMethod.getMethod();
String target = handlerMethod.getBean().getClass().getName() + "." + method.getName();
RoleOfAdmin roleOfAdmin = AuthorityAnnotationContainer.get(target);
if(roleOfAdmin != null){
OssAdmin currentUser = RequestHolder.getCurrentUser();
if(currentUser.getRole().contains(MainConstants.SYS)){
return true;
}else {
PrintWriter printWriter = response.getWriter();
ApiResult result = new ApiResult<>();
result.setCode(CommonCode.TOKEN_INVALID.getKey());
result.setMsg("用户无权限");
printWriter.write(result.toString());
return false;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
5. 拦截器配置类
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
@Autowired
RedisFeignClient redisFeignClient;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//通用拦截器,用来允许跨域请求
registry.addInterceptor(new CommonInterceptor()).addPathPatterns("/**");
// cookie拦截器,用来获取cookie信息,如果验证了cookie,会向RequestHolder里塞入用户信息
registry.addInterceptor(new TokenIntecptor(redisFeignClient)).addPathPatterns("/**")
// 排除用户登录
.excludePathPatterns("/ossadmin/login")
.excludePathPatterns("/ossadmin/logout")
registry.addInterceptor(new AuthorityInterceptor()).addPathPatterns("/**")
// 排除用户登录
.excludePathPatterns("/ossadmin/login")
.excludePathPatterns("/ossadmin/logout")
}
}