import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.i78dk.easyloan.web.common.interceptor.AuthorizationInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import java.io.IOException;
import java.util.List;
import java.util.Date;
@Configuration
public class WebAppConfiguration extends WebMvcConfigurerAdapter {
@Autowired
private AuthorizationInterceptor authorizationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 自定义拦截器,添加拦截路径和排除拦截路径
registry.addInterceptor(authorizationInterceptor).addPathPatterns("/api/78dk/web/**")
.excludePathPatterns("/swagger-ui.html");
}
// @Override
// public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
// converter.setFeatures(SerializerFeature.WriteNullListAsEmpty,
// SerializerFeature.WriteMapNullValue,
// //字符串null返回空字符串
// SerializerFeature.WriteNullStringAsEmpty,
// SerializerFeature.WriteNullBooleanAsFalse,
// SerializerFeature.WriteNullNumberAsZero,
// SerializerFeature.PrettyFormat);
// converters.add(converter);
// }
// @Bean
// public HttpMessageConverters fastJsonHttpMessageConverters() {
// //1、创建FastJson信息转换对象
// FastJsonHttpMessageConverter fastConverter=new FastJsonHttpMessageConverter();
// //2、创建FastJsonConfig对象并设定序列化规则 序列化规则详见SerializerFeature类中,后面会讲
// FastJsonConfig fastJsonConfig= new FastJsonConfig();
// fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat,SerializerFeature.WriteNonStringKeyAsString);
// //本人就坑在WriteNonStringKeyAsString 将不是String类型的key转换成String类型,否则前台无法将Json字符串转换成Json对象
//
// //如果值为null,则返回空串
// ValueFilter dateFilter = (Object var1, String var2, Object var3) -> {
// try {
// if (var3 == null && var1 != null && Date.class.isAssignableFrom(var1.getClass().getDeclaredField(var2).getType())){
// return "";
// }
// } catch (Exception e) {}
// return var3;
// };
// fastJsonConfig.setSerializeFilters(dateFilter);
//
// //4、将转换规则应用于转换对象
// fastConverter.setFastJsonConfig(fastJsonConfig);
// return new HttpMessageConverters(fastConverter);
// }
@Bean
public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
// objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化
//objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 字段保留,将null值转为""
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
jsonGenerator.writeString("");
}
});
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
return mappingJackson2HttpMessageConverter;
}
// @Bean
// public FastJsonHttpMessageConverter fastJsonHttpMessageConverter(){
// return new FastJsonHttpMessageConverter();
// }
//配置解析器
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/**");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
//配置静态资源处理
configurer.enable();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
/**
* 跨域过滤器
* @return
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4
return new CorsFilter(source);
}
}
//////////////////////////////////
import com.alibaba.fastjson.JSONObject;
import com.i78dk.easyloan.domain.system.dto.AdminRoleOrgDto;
import com.i78dk.easyloan.web.annotation.AuthToken;
import com.i78dk.easyloan.web.common.constants.ResultCodeConstants;
import com.i78dk.easyloan.web.common.context.UserContext;
import com.i78dk.easyloan.web.common.redis.RedisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;
/**
* @author zhangqi@78dk.com
* @create: 2018-11-16 15:17
*/
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
@Autowired
RedisService redisService;
private Logger log = LoggerFactory.getLogger(AuthorizationInterceptor.class);
/**
* 存放鉴权信息的Header名称,默认是AuthorToken
*/
private String httpHeaderName = "AuthorToken";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 如果打上了AuthToken注解则不需要验证token
if (method.getAnnotation(AuthToken.class) != null || handlerMethod.getBeanType().getAnnotation(AuthToken.class) != null) {
return true;
} else {
String token = request.getHeader(httpHeaderName);
log.info("token is {}", token);
if (null != token && redisService.exists(token)) {
//登录数据初始化
AdminRoleOrgDto sysAdmin = (AdminRoleOrgDto) redisService.get(token);
UserContext.set(sysAdmin);
return true;
} else {
JSONObject jsonObject = new JSONObject();
PrintWriter out = null;
try {
response.setContentType("application/json;charset=UTF-8");
jsonObject.put("code", ResultCodeConstants.CODE_S0014);
jsonObject.put("data", "");
jsonObject.put("msg", ResultCodeConstants.getMsg(ResultCodeConstants.CODE_S0014));
out = response.getWriter();
out.println(jsonObject);
return false;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != out) {
out.flush();
out.close();
}
}
}
}
return false;
}
@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 {
//执行完成清理当前线程
UserContext.clean();
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author zhangqi@78dk.com
* @description: 加上该注解的类http请求时需要进行token鉴权
* @create: 2018-11-16 15:17
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthToken {
}
/////
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
/**
* @author zhangqi@78dk.com
* @create: 2018-11-16 15:17
*/
@Component
public class Md5TokenGenerator implements TokenGenerator {
@Override
public String generate(String... strings) {
long timestamp = System.currentTimeMillis();
String tokenMeta = "";
for (String s : strings) {
tokenMeta = tokenMeta + s;
}
tokenMeta = tokenMeta + timestamp;
String token = DigestUtils.md5DigestAsHex(tokenMeta.getBytes());
return token;
}
}
@Component
public interface TokenGenerator {
public String generate(String... strings);
}
/**
登录用户信息上下文
*/
public class UserContext {
private static ThreadLocal<AdminRoleOrgDto> UserContext = new ThreadLocal<AdminRoleOrgDto>();
public static AdminRoleOrgDto get(){
if(null == UserContext.get()){
UserContext.set(new AdminRoleOrgDto());
}
return UserContext.get();
}
public static void set(AdminRoleOrgDto user){
UserContext.set(user);
}
public static void clean(){
UserContext.remove();
}
}
使用注解可参考: 跨域问题 springboot可参考:详解WebMvcConfigurer接口
文章中若有不足之处,还望指出。坚持是一种精神,分享是一种快乐!
版权声明:本文由 Ian 在 2019年02月05日发表。本文采用CC BY-NC-SA 4.0许可协议,非商业转载请注明出处,不得用于商业目的。
文章题目及链接:《微服务拦截器处理跨域验证token》