javax.validation
diff --git a/src/main/java/com/jwl/driver/server/config/AuthConfig.java b/src/main/java/com/jwl/driver/server/config/AuthConfig.java
new file mode 100644
index 0000000..4895009
--- /dev/null
+++ b/src/main/java/com/jwl/driver/server/config/AuthConfig.java
@@ -0,0 +1,34 @@
+package com.jwl.driver.server.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 权限配置类
+ */
+@ConfigurationProperties(prefix = AuthConfig.PREFIX)
+@Component
+@Data
+public class AuthConfig {
+
+
+ public static final String PREFIX = "driver.auth-config";
+
+ /**
+ * 约定为若 preAuth 为 true,则所有请求(除不需权限校验url集合noAuthEndPoints外)都需要身份认证
+ * 为 false,则所有请求(除需要权限校验url集合needAuthEndPoints外)都不需要身份认证
+ */
+ private Boolean preAuth;
+
+ /**
+ * 不需权限校验 url 集合
+ */
+ private String[] noAuthEndPoints;
+
+ /**
+ * 必须验证的权限 url 集合
+ */
+ private String[] needAuthEndPoints;
+
+}
diff --git a/src/main/java/com/jwl/driver/server/config/CorsConfig.java b/src/main/java/com/jwl/driver/server/config/CorsConfig.java
index 173928b..9ffdd7d 100644
--- a/src/main/java/com/jwl/driver/server/config/CorsConfig.java
+++ b/src/main/java/com/jwl/driver/server/config/CorsConfig.java
@@ -26,7 +26,8 @@ public class CorsConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor).addPathPatterns("/**").excludePathPatterns("/**/login",
-// "/error",
+ "/error",
+ "/webjars/**",
"/doc.html");
}
@@ -56,11 +57,6 @@ public class CorsConfig implements WebMvcConfigurer {
registry.addResourceHandler("doc.html")
.addResourceLocations("classpath:/META-INF/resources/");
- /**
- * 配置swagger-ui显示文档
- */
- registry.addResourceHandler("swagger-ui.html")
- .addResourceLocations("classpath:/META-INF/resources/");
/** 公共部分内容 */
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
diff --git a/src/main/java/com/jwl/driver/server/controller/TdSysUserController.java b/src/main/java/com/jwl/driver/server/controller/TdSysUserController.java
index 89c32b9..c1e334b 100644
--- a/src/main/java/com/jwl/driver/server/controller/TdSysUserController.java
+++ b/src/main/java/com/jwl/driver/server/controller/TdSysUserController.java
@@ -8,12 +8,11 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDateTime;
/**
*
@@ -35,9 +34,17 @@ public class TdSysUserController {
@ApiOperation("用户登陆")
@PostMapping("/login")
- public BaseResponse login(@RequestBody LoginUserDto loginUserDto) throws Exception {
+ public BaseResponse login(@RequestBody LoginUserDto loginUserDto) {
log.info("用户登录======>loginUserDto:{}", loginUserDto);
return BaseResponse.success(userService.login(loginUserDto));
}
+
+ @ApiOperation("用户登出")
+ @GetMapping("/loginOut")
+ public BaseResponse loginOut(){
+ log.info("用户登出======>{}", LocalDateTime.now());
+ return BaseResponse.success(userService.loginOut());
+ }
+
}
diff --git a/src/main/java/com/jwl/driver/server/dto/SecurityUser.java b/src/main/java/com/jwl/driver/server/dto/SecurityUser.java
new file mode 100644
index 0000000..6d7291c
--- /dev/null
+++ b/src/main/java/com/jwl/driver/server/dto/SecurityUser.java
@@ -0,0 +1,32 @@
+package com.jwl.driver.server.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class SecurityUser implements Serializable {
+
+ /**
+ * 用户标识
+ */
+ private Long userId;
+
+ /**
+ * 用户名
+ */
+ private String userName;
+
+
+ /**
+ * 用户token
+ */
+ private String token;
+
+
+}
diff --git a/src/main/java/com/jwl/driver/server/filter/TokenFilter.java b/src/main/java/com/jwl/driver/server/filter/TokenFilter.java
new file mode 100644
index 0000000..5bcf9bb
--- /dev/null
+++ b/src/main/java/com/jwl/driver/server/filter/TokenFilter.java
@@ -0,0 +1,37 @@
+package com.jwl.driver.server.filter;
+
+import cn.hutool.core.util.StrUtil;
+import com.jwl.driver.server.util.TokenThreadUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 线程保持当前token
+ */
+@Component
+public class TokenFilter extends OncePerRequestFilter {
+ private static final Logger log = LoggerFactory.getLogger(TokenFilter.class);
+
+
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+ String requestTokenHeader = request.getHeader("Authorization");
+ if (StrUtil.isBlank(requestTokenHeader)) {
+ log.warn("Bearer token 为空");
+ filterChain.doFilter((ServletRequest) request, (ServletResponse) response);
+ return;
+ }
+
+ TokenThreadUtil.setToken(requestTokenHeader);
+ filterChain.doFilter(request, response);
+ }
+}
diff --git a/src/main/java/com/jwl/driver/server/interceptor/AuthInterceptor.java b/src/main/java/com/jwl/driver/server/interceptor/AuthInterceptor.java
index a092248..57ee773 100644
--- a/src/main/java/com/jwl/driver/server/interceptor/AuthInterceptor.java
+++ b/src/main/java/com/jwl/driver/server/interceptor/AuthInterceptor.java
@@ -1,14 +1,23 @@
package com.jwl.driver.server.interceptor;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.jwl.driver.server.config.AuthConfig;
+import com.jwl.driver.server.constant.ErrorCode;
+import com.jwl.driver.server.exception.BusinessException;
import com.jwl.driver.server.redis.RedisCache;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
+import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
import java.util.Objects;
/**
@@ -18,29 +27,62 @@ import java.util.Objects;
*/
@Component
+@Slf4j
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
private RedisCache redisCache;
+ @Resource
+ private AuthConfig authConfig;
+
+
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
- if (requestURI.contains("doc.html")){
- return true;
- }
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
- String token = request.getHeader("token");
- if (StringUtils.isEmpty(token)) {
- response.getWriter().print("用户未登录,请登录后操作!");
- return false;
+ String requestTokenHeader = request.getHeader("Authorization");
+
+ Boolean preAuth = authConfig.getPreAuth();
+ ArrayList noAuthEndPoints = ListUtil.toList(authConfig.getNoAuthEndPoints());
+ ArrayList needAuthEndPoints = ListUtil.toList(authConfig.getNeedAuthEndPoints());
+
+ if (StrUtil.isBlank(requestTokenHeader)) {
+ log.warn("Authorization token 为空");
}
- Object loginStatus = redisCache.getCacheObject(token);
- if( Objects.isNull(loginStatus)){
- response.getWriter().print("登陆异常,请查看!");
- return false;
+
+ // preAuth = false,则所有请求(除需要权限校验url集合needAuthEndPoints外)都不需要身份认证
+ if (BooleanUtil.isFalse(preAuth)) {
+ Boolean contains = needAuthEndPoints.contains(requestURI);
+ // 必须登录的接口 && token为空
+ if (contains && StrUtil.isBlank(requestTokenHeader)) {
+ throw new BusinessException(ErrorCode.AUTH_ERROR, "尚未授权登录");
+ }
+ }else {
+ // preAuth = true;
+ // 配置文件无需登录的接口
+ Boolean contains = noAuthEndPoints.contains(requestURI);
+ // 具备排除标志的接口
+ Boolean excludeFlag = Boolean.FALSE;
+ for (String exclude : needAuthEndPoints) {
+ if (requestURI.contains(exclude)) {
+ excludeFlag = Boolean.TRUE;
+ break;
+ }
+ }
+ if (!contains && !excludeFlag && StrUtil.isBlank(requestTokenHeader)) {
+ throw new BusinessException(ErrorCode.AUTH_ERROR, "尚未授权登录");
+ }
}
+
+ if (StrUtil.isNotBlank(requestTokenHeader)){
+ Object loginStatus = redisCache.getCacheObject(requestTokenHeader);
+ if( Objects.isNull(loginStatus)){
+ throw new BusinessException(ErrorCode.AUTH_ERROR, "登陆已过期");
+ }
+ }
+
return true;
}
diff --git a/src/main/java/com/jwl/driver/server/service/ITdSysUserService.java b/src/main/java/com/jwl/driver/server/service/ITdSysUserService.java
index d4b3f44..0b32459 100644
--- a/src/main/java/com/jwl/driver/server/service/ITdSysUserService.java
+++ b/src/main/java/com/jwl/driver/server/service/ITdSysUserService.java
@@ -15,5 +15,16 @@ import com.jwl.driver.server.vo.LoginUserVo;
*/
public interface ITdSysUserService extends IService {
+ /**
+ * 用户登陆
+ * @param loginUserDto
+ * @return
+ */
LoginUserVo login(LoginUserDto loginUserDto);
+
+ /**
+ * 用户登出
+ * @return
+ */
+ Boolean loginOut();
}
diff --git a/src/main/java/com/jwl/driver/server/service/impl/TdSysUserServiceImpl.java b/src/main/java/com/jwl/driver/server/service/impl/TdSysUserServiceImpl.java
index a07e09c..4bde82a 100644
--- a/src/main/java/com/jwl/driver/server/service/impl/TdSysUserServiceImpl.java
+++ b/src/main/java/com/jwl/driver/server/service/impl/TdSysUserServiceImpl.java
@@ -1,17 +1,22 @@
package com.jwl.driver.server.service.impl;
+import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jwl.driver.server.dto.LoginUserDto;
import com.jwl.driver.server.entity.TdSysUser;
+import com.jwl.driver.server.exception.BusinessException;
import com.jwl.driver.server.mapper.TdSysUserMapper;
import com.jwl.driver.server.redis.RedisCache;
import com.jwl.driver.server.service.ITdSysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jwl.driver.server.util.TokenThreadUtil;
import com.jwl.driver.server.vo.LoginUserVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.time.LocalDateTime;
import java.util.UUID;
/**
@@ -29,13 +34,24 @@ public class TdSysUserServiceImpl extends ServiceImpl cond = new LambdaQueryWrapper()
.eq(TdSysUser::getPhone,"18255439337");
+ //用户不存在则直接注册登陆
TdSysUser tdSysUser = this.baseMapper.selectOne(cond);
if (tdSysUser == null){
- //创建用户
+ tdSysUser = new TdSysUser()
+ .setUserName("车友")
+ .setAvatar("")
+ .setPhone(loginUserDto.getPhone())
+ .setCreateTime(LocalDateTime.now());
+ int insert = this.getBaseMapper().insert(tdSysUser);
+ if (insert != 1){
+ throw new BusinessException("用户注册异常");
+ }
}
String token = UUID.randomUUID().toString();
@@ -45,8 +61,14 @@ public class TdSysUserServiceImpl extends ServiceImplgetBean(RedisCache.class);
+
+
+ /**
+ * 获取当前登录人信息
+ * @return
+ */
+ public static SecurityUser getLoginUser() {
+ String token = TokenThreadUtil.getToken();
+ if (StrUtil.isBlank(token))
+ throw new BusinessException(ErrorCode.AUTH_ERROR, "尚未登录");
+ SecurityUser securityUser = null;
+ TdSysUser tdSysUser = redisCache.getCacheObject(token);
+
+ if (Objects.isNull(securityUser)){
+ throw new BusinessException(ErrorCode.AUTH_ERROR, "登录信息已失效");
+ }
+ BeanUtils.copyProperties(tdSysUser,securityUser);
+ securityUser.setToken(token);
+
+ return securityUser;
+ }
+
+ /**
+ * 获取当前登录人用户编号
+ * @return
+ */
+ public static Long getUserId() {
+ Long userId = null;
+ SecurityUser loginUser = SecurityUtil.getLoginUser();
+ if (null != loginUser) {
+ userId = loginUser.getUserId();
+ }
+
+ return userId;
+ }
+
+
+}
diff --git a/src/main/java/com/jwl/driver/server/util/SpringAsyncUtil.java b/src/main/java/com/jwl/driver/server/util/SpringAsyncUtil.java
new file mode 100644
index 0000000..36d1aaf
--- /dev/null
+++ b/src/main/java/com/jwl/driver/server/util/SpringAsyncUtil.java
@@ -0,0 +1,62 @@
+package com.jwl.driver.server.util;
+
+
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+public final class SpringAsyncUtil implements BeanFactoryPostProcessor, ApplicationContextAware {
+ private static ConfigurableListableBeanFactory beanFactory;
+
+ private static ApplicationContext applicationContext;
+
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ SpringAsyncUtil.beanFactory = beanFactory;
+ }
+
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ SpringAsyncUtil.applicationContext = applicationContext;
+ }
+
+ public static T getBean(String name) throws BeansException {
+ return (T)beanFactory.getBean(name);
+ }
+
+ public static T getBean(Class clz) throws BeansException {
+ T result = (T)beanFactory.getBean(clz);
+ return result;
+ }
+
+ public static boolean containsBean(String name) {
+ return beanFactory.containsBean(name);
+ }
+
+ public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
+ return beanFactory.isSingleton(name);
+ }
+
+ public static Class> getType(String name) throws NoSuchBeanDefinitionException {
+ return beanFactory.getType(name);
+ }
+
+ public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
+ return beanFactory.getAliases(name);
+ }
+
+ public static T getAopProxy(T invoker) {
+ return (T)AopContext.currentProxy();
+ }
+
+ public static String[] getActiveProfiles() {
+ return applicationContext.getEnvironment().getActiveProfiles();
+ }
+
+ public static String getActiveProfile() {
+ String[] activeProfiles = getActiveProfiles();
+ return (activeProfiles.length > 0) ? activeProfiles[0] : null;
+ }
+}
diff --git a/src/main/java/com/jwl/driver/server/util/TokenThreadUtil.java b/src/main/java/com/jwl/driver/server/util/TokenThreadUtil.java
new file mode 100644
index 0000000..72eecb9
--- /dev/null
+++ b/src/main/java/com/jwl/driver/server/util/TokenThreadUtil.java
@@ -0,0 +1,23 @@
+package com.jwl.driver.server.util;
+
+import cn.hutool.core.util.StrUtil;
+
+/**
+ * 线程变量-token
+ */
+public class TokenThreadUtil {
+ private static ThreadLocal threadLocal = new ThreadLocal<>();
+
+ public static void setToken(String token) {
+ if (StrUtil.isNotBlank(token))
+ threadLocal.set(token);
+ }
+
+ public static String getToken() {
+ return threadLocal.get();
+ }
+
+ public static void remove() {
+ threadLocal.remove();
+ }
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index d84c9b4..0b533ea 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -1,7 +1,7 @@
server:
port: 8888
-# servlet:
-# context-path: '/driver-api'
+ servlet:
+ context-path: '/driver-api'
spring:
application:
@@ -29,3 +29,18 @@ pagehelper:
knife4j:
# 是否开启增强模式
enable: true
+
+# 是否需要校验token
+driver:
+ auth-config:
+ # 约定为若 preAuth 为 true,则所有请求(除不需权限校验url集合noAuthEndPoints外)都需要身份认证
+ # 为 false,则所有请求(除需要权限校验url集合needAuthEndPoints外)都不需要身份认证
+ preAuth: true
+ # 不需权限校验url集合
+ noAuthEndPoints:
+ - /driver-api/v2/api-docs
+ - /driver-api/swagger-resources
+ - /driver-api/favicon.ico
+
+ # 需要权限校验url集合
+ needAuthEndPoints: