从"Blog"仓库中分离出来
This commit is contained in:
38
src/main/java/cn/celess/blog/configuration/CorsConfig.java
Normal file
38
src/main/java/cn/celess/blog/configuration/CorsConfig.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package cn.celess.blog.configuration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* @author : xiaohai
|
||||
* @date : 2019/03/30 19:55
|
||||
* 跨域
|
||||
*/
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.addAllowedOrigin("http://celess.cn");
|
||||
config.addAllowedOrigin("http://www.celess.cn");
|
||||
config.addAllowedOrigin("https://celess.cn");
|
||||
config.addAllowedOrigin("https://www.celess.cn");
|
||||
// 本地调试时的跨域
|
||||
config.addAllowedOrigin("http://localhost:4200");
|
||||
config.addAllowedOrigin("http://127.0.0.1:4200");
|
||||
config.addAllowedHeader("*");
|
||||
config.addAllowedMethod("OPTIONS");
|
||||
config.addAllowedMethod("GET");
|
||||
config.addAllowedMethod("POST");
|
||||
config.addAllowedMethod("PUT");
|
||||
config.addAllowedMethod("DELETE");
|
||||
config.setAllowCredentials(true);
|
||||
config.setMaxAge(10800L);
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
}
|
||||
41
src/main/java/cn/celess/blog/configuration/DruidConfig.java
Normal file
41
src/main/java/cn/celess/blog/configuration/DruidConfig.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package cn.celess.blog.configuration;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author : xiaohai
|
||||
* @date : 2019/03/28 14:26
|
||||
*/
|
||||
@Configuration
|
||||
public class DruidConfig {
|
||||
@Value("${spring.datasource.url}")
|
||||
private String dbUrl;
|
||||
|
||||
@Value("${spring.datasource.username}")
|
||||
private String username;
|
||||
|
||||
@Value("${spring.datasource.password}")
|
||||
private String password;
|
||||
|
||||
@Value("${spring.datasource.driver-class-name}")
|
||||
private String driverClassName;
|
||||
|
||||
@Bean
|
||||
public DruidDataSource druidDataSource() {
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
|
||||
// 数据库基本信息
|
||||
dataSource.setUrl(dbUrl);
|
||||
dataSource.setUsername(username);
|
||||
dataSource.setPassword(password);
|
||||
|
||||
// 数据库连接池配置
|
||||
dataSource.setInitialSize(10);
|
||||
dataSource.setMinIdle(10);
|
||||
dataSource.setMaxActive(100);
|
||||
return dataSource;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cn.celess.blog.configuration;
|
||||
|
||||
import cn.celess.blog.configuration.filter.AuthenticationFilter;
|
||||
import cn.celess.blog.configuration.filter.MultipleSubmitFilter;
|
||||
import cn.celess.blog.configuration.filter.VisitorRecord;
|
||||
import cn.celess.blog.configuration.listener.SessionListener;
|
||||
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @Author: 小海
|
||||
* @Date: 2019/10/18 14:19
|
||||
* @Description:
|
||||
*/
|
||||
@Configuration
|
||||
public class InterceptorConfig implements WebMvcConfigurer {
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new MultipleSubmitFilter()).addPathPatterns("/*");
|
||||
registry.addInterceptor(authenticationFilter()).addPathPatterns("/**");
|
||||
|
||||
// visitor 输出信息杂乱 暂时放弃使用
|
||||
// registry.addInterceptor(new VisitorRecord()).addPathPatterns("/*");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationFilter authenticationFilter() {
|
||||
return new AuthenticationFilter();
|
||||
}
|
||||
|
||||
// // session listener register bean
|
||||
// @Bean
|
||||
// public ServletListenerRegistrationBean<SessionListener> servletListenerRegistrationBean() {
|
||||
// ServletListenerRegistrationBean<SessionListener> slrBean = new ServletListenerRegistrationBean<SessionListener>();
|
||||
// slrBean.setListener(new SessionListener());
|
||||
// return slrBean;
|
||||
// }
|
||||
}
|
||||
72
src/main/java/cn/celess/blog/configuration/RedisConfig.java
Normal file
72
src/main/java/cn/celess/blog/configuration/RedisConfig.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package cn.celess.blog.configuration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
* @author : xiaohai
|
||||
* @date : 2019/05/22 17:35
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
/**
|
||||
* 缓存的命名前缀
|
||||
*
|
||||
* @return KeyGenerator
|
||||
*/
|
||||
@Override
|
||||
@Bean
|
||||
public KeyGenerator keyGenerator() {
|
||||
return new KeyGenerator() {
|
||||
@Override
|
||||
public Object generate(Object target, Method method, Object... params) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String name = target.getClass().getName();
|
||||
sb.append(name.substring(name.lastIndexOf(".") + 1));
|
||||
sb.append(":");
|
||||
sb.append(method.getName());
|
||||
for (Object obj : params) {
|
||||
sb.append("-").append(obj.toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置redisTemplate
|
||||
*
|
||||
* @param redisConnectionFactory redisConnectionFactory
|
||||
* @return redisTemplate
|
||||
*/
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
jackson2JsonRedisSerializer.setObjectMapper(om);
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
|
||||
template.setConnectionFactory(redisConnectionFactory);
|
||||
template.setKeySerializer(jackson2JsonRedisSerializer);
|
||||
template.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
template.setHashKeySerializer(jackson2JsonRedisSerializer);
|
||||
template.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.celess.blog.configuration;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
|
||||
/**
|
||||
* @author : xiaohai
|
||||
* @date : 2019/03/28 15:55
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Value("${spring.profiles.active}")
|
||||
private String environment;
|
||||
|
||||
@Bean
|
||||
public Docket createRestApi() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.enable("dev".equals(environment))
|
||||
.apiInfo(apiInfo())
|
||||
.select()
|
||||
.apis(RequestHandlerSelectors.basePackage("cn.celess.blog"))
|
||||
.paths(PathSelectors.any())
|
||||
.build();
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.title("小海博客的APi")
|
||||
.description("小海博客的APi")
|
||||
.contact("小海")
|
||||
.version("1.0")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package cn.celess.blog.configuration.filter;
|
||||
|
||||
import cn.celess.blog.enmu.ResponseEnum;
|
||||
import cn.celess.blog.service.UserService;
|
||||
import cn.celess.blog.util.JwtUtil;
|
||||
import cn.celess.blog.util.RedisUtil;
|
||||
import cn.celess.blog.util.ResponseUtil;
|
||||
import net.sf.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @Author: 小海
|
||||
* @Date: 2019/11/16 11:21
|
||||
* @Description: 鉴权拦截器
|
||||
*/
|
||||
public class AuthenticationFilter implements HandlerInterceptor {
|
||||
@Autowired
|
||||
JwtUtil jwtUtil;
|
||||
@Autowired
|
||||
RedisUtil redisUtil;
|
||||
@Autowired
|
||||
UserService userService;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthenticationFilter.class);
|
||||
|
||||
private static final String USER_PREFIX = "/user";
|
||||
private static final String ADMIN_PREFIX = "/admin";
|
||||
private static final String ROLE_ADMIN = "admin";
|
||||
private static final String ROLE_USER = "user";
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
String path = request.getRequestURI();
|
||||
path = path.replaceAll("/+", "/");
|
||||
int indexOf = path.indexOf("/", 1);
|
||||
String rootPath = indexOf == -1 ? path : path.substring(0, indexOf);
|
||||
// 不需要鉴权的路径
|
||||
if (!USER_PREFIX.equals(rootPath.toLowerCase()) && !ADMIN_PREFIX.equals(rootPath.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String jwtStr = request.getHeader("Authorization");
|
||||
if (jwtStr == null || jwtStr.isEmpty()) {
|
||||
return writeResponse(ResponseEnum.HAVE_NOT_LOG_IN, response, request);
|
||||
}
|
||||
if (jwtUtil.isTokenExpired(jwtStr)) {
|
||||
return writeResponse(ResponseEnum.LOGIN_EXPIRED, response, request);
|
||||
}
|
||||
String email = jwtUtil.getUsernameFromToken(jwtStr);
|
||||
if (!redisUtil.hasKey(email + "-login") || jwtUtil.isTokenExpired(jwtStr)) {
|
||||
// 登陆过期
|
||||
return writeResponse(ResponseEnum.LOGIN_EXPIRED, response, request);
|
||||
}
|
||||
String role = userService.getUserRoleByEmail(email);
|
||||
if (role.equals(ROLE_ADMIN)) {
|
||||
// admin
|
||||
return true;
|
||||
}
|
||||
if (role.equals(ROLE_USER) && !rootPath.equals(ADMIN_PREFIX)) {
|
||||
// user not admin page
|
||||
return true;
|
||||
}
|
||||
return writeResponse(ResponseEnum.PERMISSION_ERROR, response, request);
|
||||
}
|
||||
|
||||
private boolean writeResponse(ResponseEnum e, HttpServletResponse response, HttpServletRequest request) {
|
||||
response.setHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
try {
|
||||
logger.info("鉴权失败,[code:{},msg:{},path:{}]", e.getCode(), e.getMsg(), request.getRequestURI() + "?" + request.getQueryString());
|
||||
response.getWriter().println(JSONObject.fromObject(ResponseUtil.response(e, null)));
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package cn.celess.blog.configuration.filter;
|
||||
|
||||
import cn.celess.blog.enmu.ResponseEnum;
|
||||
import cn.celess.blog.entity.Response;
|
||||
import cn.celess.blog.util.RequestUtil;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @Author: 小海
|
||||
* @Date: 2019/10/18 13:46
|
||||
* @Description: 多次请求拦截器
|
||||
*/
|
||||
public class MultipleSubmitFilter implements HandlerInterceptor {
|
||||
private static final int WAIT_TIME = 200;// 多次提交中间的间隔
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
Long lastSubmitTime = (Long) request.getSession().getAttribute("lastSubmitTime");
|
||||
String completeUrl = (String) request.getSession().getAttribute("completeUrl&method");
|
||||
if (lastSubmitTime == null || completeUrl == null) {
|
||||
return true;
|
||||
}
|
||||
if (System.currentTimeMillis() - lastSubmitTime < WAIT_TIME && RequestUtil.getCompleteUrlAndMethod(request).equals(completeUrl)) {
|
||||
// 请求参数和路径均相同 且请求时间间隔小于 WAIT_TIME
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
Response result = new Response(ResponseEnum.FAILURE.getCode(), "重复请求", null, System.currentTimeMillis());
|
||||
response.getWriter().println(result.toString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||
HttpSession session = request.getSession();
|
||||
session.setAttribute("lastSubmitTime", System.currentTimeMillis());
|
||||
session.setAttribute("completeUrl&method", RequestUtil.getCompleteUrlAndMethod(request));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.celess.blog.configuration.filter;
|
||||
|
||||
import cn.celess.blog.util.RequestUtil;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @Author: 小海
|
||||
* @Date: 2019/10/18 15:38
|
||||
* @Description: 记录访问情况
|
||||
*/
|
||||
@Configuration
|
||||
public class VisitorRecord implements HandlerInterceptor {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
HttpSession session = request.getSession();
|
||||
HashMap<String, Integer> visitDetail = (HashMap<String, Integer>) session.getAttribute("visitDetail");
|
||||
// 获取访问次数
|
||||
Integer count = visitDetail.get(RequestUtil.getCompleteUrlAndMethod(request));
|
||||
// 自增
|
||||
count = count == null ? 1 : ++count;
|
||||
// 更新
|
||||
visitDetail.put(RequestUtil.getCompleteUrlAndMethod(request), count);
|
||||
session.setAttribute("ip",request.getRemoteAddr());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package cn.celess.blog.configuration.listener;
|
||||
|
||||
import cn.celess.blog.entity.User;
|
||||
import cn.celess.blog.util.RedisUserUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.annotation.WebListener;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSessionEvent;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @Author: 小海
|
||||
* @Date: 2019/10/18 15:33
|
||||
* @Description: 监听session的情况
|
||||
*/
|
||||
@WebListener
|
||||
public class SessionListener implements HttpSessionListener {
|
||||
@Autowired
|
||||
RedisUserUtil redisUserUtil;
|
||||
@Autowired
|
||||
HttpServletRequest request;
|
||||
private static final Logger logger = LoggerFactory.getLogger(SessionListener.class);
|
||||
|
||||
@Override
|
||||
public void sessionCreated(HttpSessionEvent se) {
|
||||
// TODO : can move 'visit' api to here
|
||||
se.getSession().setAttribute("visitDetail", new HashMap<String, Integer>());
|
||||
// se.getSession().setMaxInactiveInterval(10);// 10s for debug
|
||||
logger.info("新增一个Session[{}]", se.getSession().getId());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void sessionDestroyed(HttpSessionEvent se) {
|
||||
HashMap<String, Integer> visitDetail = (HashMap<String, Integer>) se.getSession().getAttribute("visitDetail");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("ip => ").append(se.getSession().getAttribute("ip"));
|
||||
User user = redisUserUtil.get(request);
|
||||
sb.append("\t登录情况 => ");
|
||||
sb.append(user == null ? "游客访问" : user.getEmail());
|
||||
visitDetail.forEach((s, integer) -> {
|
||||
sb.append("\n").append("Method:[").append(s.split(":")[1]).append("]\tTimes:[").append(integer).append("]\tPath:[").append(s.split(":")[0]).append("]");
|
||||
});
|
||||
logger.info(sb.toString());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user