SpringCloud自定义注解实现用户权限拦截

       我们平时在开发的时候,通常使用过滤器,拦截器,网关等等实现用户权限的校验、白名单的拦截等,今天我们在springcloud中使用自定义注解的方式来实现用户必须登录的情况下才能访问某个接口或者controller。

1.定义好注解:

package com.meiyibao.annotation;

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;

/**
 *   必须登录的注解,可以直接使用在方法上,方法上面使用以后,该方法必须有用户登录,否则直接会返回没有权限的异常
 * 
 * @author root
 *
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target({ ElementType.TYPE, ElementType.METHOD }) // 1.接口、类、枚举、注解 2.方法
public @interface MustLogin {
	public String value() default "";
}

2.定义拦截器(我这里包括了三个端的调用鉴权,有APP客户端,后台管理系统,和PC端的个人中心),另外,用户登录以后,需要把用户信息保存在redis中:

package com.meiyibao.interceptor;


import com.alibaba.fastjson.JSON;
import com.ctrip.framework.apollo.Config;
import com.meiyibao.annotation.Auth;
import com.meiyibao.annotation.MustLogin;
import com.meiyibao.annotation.RequireUser;
import com.meiyibao.annotation.WhiteIpAuth;
import com.meiyibao.bean.dto.SysUser;
import com.meiyibao.bean.dto.User;
import com.meiyibao.easycoal.framework.metadata.MybData;
import com.meiyibao.constants.MybConstants;
import com.meiyibao.redis.RedisUtil;
import com.meiyibao.util.ip.AgentUtil;
import com.meiyibao.util.json.JSONHelper;
import com.meiyibao.util.regex.ValidateHelper;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public interface BaseHandlerInterceptorAdapter {


    default <T extends Annotation> T findAnnotation(HandlerMethod handler, Class<T> annotationType) {
        T annotation = handler.getBeanType().getAnnotation(annotationType);
        if (annotation != null)
            return annotation;
        return handler.getMethodAnnotation(annotationType);
    }

    /**
     * 用户鉴权
     *
     * @param request
     * @param response
     * @param handler
     * @return
     */
    default boolean basePreHandle(HttpServletRequest request, HttpServletResponse response, Object handler, RedisUtil redis, String key, Config config) {
        try {
            if (handler instanceof HandlerMethod && handler != null) {
                //必须登录
                MustLogin mustLogin = findAnnotation((HandlerMethod) handler, MustLogin.class);
                if (mustLogin != null) {
                    Object user = getLoginUser(request, redis, key);
                    if (user == null) {
                        responeWrite(response, JSONHelper.convertToJSON(MybData.error(MybConstants.LOGIN_EXCEPTION_CODE, MybConstants.EXCEPTION_MUST_LOGIN_ERROR)));
                        return false;
                    } else {
                        request.setAttribute(MybConstants.CURRENT_USER, user);
                        return true;
                    }
                }
                //获取用户信息封装到request中
                RequireUser requireUser = findAnnotation((HandlerMethod) handler, RequireUser.class);
                if (requireUser != null) {
                    Object user = getLoginUser(request, redis, key);
                    request.setAttribute(MybConstants.CURRENT_USER, user);
                }
                Auth auth = findAnnotation((HandlerMethod) handler, Auth.class);
                // 新版用户权限要处理
                if (auth != null) {
                    return false;
                }
                // IP白名单
                WhiteIpAuth whiteIpAuth = findAnnotation((HandlerMethod) handler, WhiteIpAuth.class);
                if (whiteIpAuth != null) {
                    String[] ipArray = config.getProperty("white.ip", "").split(",");
                    // ip白名单过滤
                    List<String> list = Arrays.asList(ipArray);
                    String ip = AgentUtil.getIpAddr(request);
                    if (ipArray == null || list.indexOf(ip) == -1) {
                        responeWrite(response, JSONHelper.convertToJSON(MybData.error(MybConstants.EXCEPTION_IP_AUTH_ERROR)));
                        return false;
                    }
                }
            }
            return true;
        } catch (Exception ex) {
            return false;
        }
    }


    /**
     * 检查用户是否登录
     */
    default Object getLoginUser(HttpServletRequest request, RedisUtil redis, String key) {
        Object user = null;
        String token = request.getHeader(MybConstants.AUTHORIZATION);
        if (ValidateHelper.isNullOrEmpty(token)) {
            token = request.getParameter(MybConstants.AUTHORIZATION);
        }
        if (ValidateHelper.isNullOrEmpty(token)) {
            return user;
        }
        // 后台管理系统的鉴权
        if (key.equals(MybConstants.TOKEN_ADMIN_USER_KEY)) {
            String objStr = redis.getString(key + token);
            if (objStr != null) {
                user = JSON.parseObject(objStr, SysUser.class);
            }
        }
        //APP系统的鉴权 PC个人中心的鉴权
        else if (key.equals(MybConstants.TOKEN_APP_USER_KEY) || key.equals(MybConstants.TOKEN_WEB_USER_KEY)) {
            List<String> keys = redis.scanMatch(key + "*" + token);
            String objStr;
            Iterator<String> iterator = keys.iterator();
            while (iterator.hasNext()) {
                objStr = redis.getString(iterator.next());
                if (objStr != null) {
                    user = JSON.parseObject(objStr, User.class);
                }
            }
        }
        return user;
    }

    default void responeWrite(HttpServletResponse response, String content) throws IOException {
        response.setContentType(MybConstants.JSON_FORMAT);
        response.setStatus(MybConstants.HTTP_STATUS_SUCCESS_CODE);
        response.getWriter().write(content);
    }

}

 

3.实现BaseHandlerInterceptorAdapter接口进行调用,我这里是PC端服务端工程调用

package com.meiyibao.interceptor;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
import com.meiyibao.constants.MybConstants;
import com.meiyibao.redis.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

/**
 * 拦截器,用来拦截 后台管理系统或者 自定义的请求, 另外还用来处理回话过期的拦截和用户鉴权
 *
 * @author Ray
 */
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter implements BaseHandlerInterceptorAdapter {
    @Autowired
    private RedisUtil redis;

    @ApolloConfig
    private Config config;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        return basePreHandle(request, response, handler, redis, MybConstants.TOKEN_ADMIN_USER_KEY, config);
    }
}

4.配置拦截url,这里配置所有的url请求都必须要进入BaseHandlerInterceptorAdapter中:

package com.meiyibao.config;

import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.meiyibao.interceptor.AuthInterceptor;
import com.meiyibao.util.common.CustomFastJsonConfig;
import com.meiyibao.util.time.TimeHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 拦截器配置
 *
 */
@Configuration
public class MvcConfig extends WebMvcConfigurationSupport  {
	@Autowired
	private AuthInterceptor myInterceptor;
	@Autowired
	private RequestMappingHandlerAdapter handlerAdapter;
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/**");
		super.addResourceHandlers(registry);
	}

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		FastJsonHttpMessageConverter  fastJsonHttpMessageConverter=new FastJsonHttpMessageConverter();
		fastJsonHttpMessageConverter.setFastJsonConfig(CustomFastJsonConfig.FAST_JSON_CONFIG);
		List<MediaType> mediaTypes=new ArrayList<>();
		mediaTypes.add(MediaType.APPLICATION_JSON);
		mediaTypes.add(new MediaType("application", "*+json"));
		fastJsonHttpMessageConverter.setSupportedMediaTypes(mediaTypes);
        converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
        converters.add(fastJsonHttpMessageConverter);
	}

	@Override
	public void configurePathMatch(PathMatchConfigurer configurer) {

	}

	private CorsConfiguration buildConfig() {
		CorsConfiguration corsConfiguration = new CorsConfiguration();
		corsConfiguration.addAllowedOrigin("*");
		corsConfiguration.addAllowedHeader("*");
		corsConfiguration.addAllowedMethod("GET");
		corsConfiguration.addAllowedMethod("POST");
		corsConfiguration.addAllowedMethod("OPTIONS");
		return corsConfiguration;
	}

	@Bean
	public CorsFilter corsFilter() {
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		// 4 对接口配置跨域设置
		source.registerCorsConfiguration("/**", buildConfig());
		return new CorsFilter(source);
	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(myInterceptor);
		super.addInterceptors(registry);
	}
	@PostConstruct
	public void initEditableValidation() {
		ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) handlerAdapter.getWebBindingInitializer();
		if (initializer.getConversionService() != null) {
			GenericConversionService genericConversionService = (GenericConversionService) initializer.getConversionService();
			genericConversionService.addConverter(new Converter<String, Date>() {
				@Override
				public Date convert(String source) {
					return TimeHelper.convert(source);
				}
			});
		}
	}
}

4.使用,在controller中,只需要加上mustLogin注解就可以简单越快的使用了

 /**
     * 订单历史方案列表
     *
     * @param po
     * @return
     */
    @MustLogin
    @PostMapping("/admin/listOrderSearchSolutionHistory")
    public Object listOrderSearchSolutionHistory(@RequestBody OrderSearchSolutionHistoryPo po) {
        if (ValidateHelper.isNullOrEmpty(po.getOrderId())) {
            return MybData.error("orderId不能为空");
        }
        return MybData.success(orderSearchSolutionHistoryService.listOrderSearchSolutionHistory(po));
    }

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值