Skip to content

Commit

Permalink
增加 auth 认证拦截器
Browse files Browse the repository at this point in the history
  • Loading branch information
YunaiV committed Apr 21, 2020
1 parent 6bcad5d commit eec8f08
Show file tree
Hide file tree
Showing 56 changed files with 621 additions and 439 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import cn.iocoder.common.framework.vo.CommonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -100,6 +101,11 @@ public static ServiceException exception(Integer code, String messagePattern, Ob
return new ServiceException(code, message);
}

public static ServiceException exception(CommonResult result) {
Assert.isTrue(result.isError(), "结果必须是错误的");
return new ServiceException(result.getCode(), result.getMessage());
}

/**
* 将错误编号对应的消息使用 params 进行格式化。
*
Expand Down
45 changes: 45 additions & 0 deletions common/mall-spring-boot-starter-security/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>mall-spring-boot-starter-security</artifactId>

<dependencies>
<!-- Mall 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>system-rpc-api</artifactId>
<version>1.0-SNAPSHOT</version>
<optional>true</optional>
</dependency>

<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-web</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

<!-- RPC 相关 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cn.iocoder.mall.security.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(name = {"cn.iocoder.mall.system.rpc.api.systemlog.SystemLogRPC", "org.apache.dubbo.config.annotation.Reference"})
public class CommonSecurityAutoConfiguration implements WebMvcConfigurer {

// ========== 拦截器相关 ==========


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package cn.iocoder.mall.security.core.account;

import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.system.rpc.api.oauth2.OAuth2RPC;
import cn.iocoder.mall.system.rpc.request.oauth2.OAuth2AccessTokenAuthenticateRequest;
import cn.iocoder.mall.system.rpc.response.oauth2.OAuth2AccessTokenResponse;
import cn.iocoder.mall.web.core.util.CommonWebUtil;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

public class AccountAuthInterceptor extends HandlerInterceptorAdapter {

private Logger logger = LoggerFactory.getLogger(getClass());

@Reference(validation = "true", version = "${dubbo.consumer.OAuth2RPC.version}")
private OAuth2RPC oauth2RPC;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 执行认证
String accessToken = HttpUtil.obtainAuthorization(request);
OAuth2AccessTokenAuthenticateRequest oauth2AccessTokenAuthenticateRequest = new OAuth2AccessTokenAuthenticateRequest()
.setAccessToken(accessToken).setIp(HttpUtil.getIp(request));
CommonResult<OAuth2AccessTokenResponse> oauth2AccessTokenResponseResult = oauth2RPC.authenticate(oauth2AccessTokenAuthenticateRequest);
if (oauth2AccessTokenResponseResult.isError()) { // TODO 有一个问题点,假设 token 认证失败,但是该 url 是无需认证的,是不是一样能够执行过去?
throw ServiceExceptionUtil.exception(oauth2AccessTokenResponseResult);
}
// 设置账号编号
CommonWebUtil.setAccountId(request, oauth2AccessTokenResponseResult.getData().getAccountId());
return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package cn.iocoder.mall.security.core;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package cn.iocoder.mall.security;
1 change: 1 addition & 0 deletions common/mall-spring-boot-starter-web/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package cn.iocoder.mall.web.config;

import cn.iocoder.mall.web.constant.CommonMallConstants;
import cn.iocoder.mall.web.handler.GlobalResponseBodyHandler;
import cn.iocoder.mall.web.interceptor.AccessLogInterceptor;
import cn.iocoder.mall.web.core.constant.CommonMallConstants;
import cn.iocoder.mall.web.core.handler.GlobalExceptionHandler;
import cn.iocoder.mall.web.core.handler.GlobalResponseBodyHandler;
import cn.iocoder.mall.web.core.interceptor.AccessLogInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
Expand All @@ -28,10 +29,16 @@ public GlobalResponseBodyHandler globalResponseBodyHandler() {
return new GlobalResponseBodyHandler();
}

@Bean
@ConditionalOnMissingBean(GlobalExceptionHandler.class)
public GlobalExceptionHandler globalExceptionHandler() {
return new GlobalExceptionHandler();
}

// ========== 拦截器相关 ==========

@Bean
@ConditionalOnClass(name = "cn.iocoder.mall.system.rpc.api.SystemLogRPC")
@ConditionalOnClass(name = {"cn.iocoder.mall.system.rpc.api.systemlog.SystemLogRPC", "org.apache.dubbo.config.annotation.Reference"})
@ConditionalOnMissingBean(AccessLogInterceptor.class)
public AccessLogInterceptor accessLogInterceptor() {
return new AccessLogInterceptor();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cn.iocoder.mall.web.constant;
package cn.iocoder.mall.web.core.constant;

public interface CommonMallConstants {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package cn.iocoder.mall.spring.boot.web.handler;
package cn.iocoder.mall.web.core.handler;

import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.common.framework.util.ExceptionUtil;
import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.util.MallUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.system.api.SystemLogService;
import cn.iocoder.mall.system.api.dto.systemlog.AccessLogAddDTO;
import cn.iocoder.mall.system.api.dto.systemlog.ExceptionLogAddDTO;
import cn.iocoder.mall.system.rpc.api.systemlog.SystemLogRPC;
import cn.iocoder.mall.system.rpc.request.systemlog.ExceptionLogAddRequest;
import cn.iocoder.mall.web.core.util.CommonWebUtil;
import com.alibaba.fastjson.JSON;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Metrics;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
Expand All @@ -20,68 +18,69 @@
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.Assert;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.Date;

@ControllerAdvice
/**
* 全局异常处理器,将 Exception 翻译成 CommonResult + 对应的异常编号
*/
@RestControllerAdvice
public class GlobalExceptionHandler {

/**
* 异常总数 Metrics
*/
private static final Counter EXCEPTION_COUNTER = Metrics.counter("mall.exception.total");
// TODO 芋艿,应该还有其它的异常,需要进行翻译


// /**
// * 异常总数 Metrics
// */
// private static final Counter EXCEPTION_COUNTER = Metrics.counter("mall.exception.total");

private Logger logger = LoggerFactory.getLogger(getClass());

@Value("${spring.application.name}")
private String applicationName;

@Reference(validation = "true", version = "${dubbo.consumer.AdminAccessLogService.version:1.0.0}")
private SystemLogService systemLogService;
// TODO 目前存在一个问题,如果未引入 system-rpc-api 依赖,GlobalExceptionHandler 会报类不存在。未来封装出 Repository 解决该问题
@Reference(validation = "true", version = "${dubbo.consumer.SystemLogRPC.version}")
private SystemLogRPC systemLogRPC;

// 逻辑异常
@ResponseBody
@ExceptionHandler(value = ServiceException.class)
public CommonResult serviceExceptionHandler(HttpServletRequest req, ServiceException ex) {
logger.debug("[serviceExceptionHandler]", ex);
return CommonResult.error(ex.getCode(), ex.getMessage());
}

// Spring MVC 参数不正确
@ResponseBody
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public CommonResult missingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException ex) {
logger.warn("[missingServletRequestParameterExceptionHandler]", ex);
return CommonResult.error(SysErrorCodeEnum.MISSING_REQUEST_PARAM_ERROR.getCode(), SysErrorCodeEnum.MISSING_REQUEST_PARAM_ERROR.getMessage() + ":" + ex.getMessage());
}

@ResponseBody
@ExceptionHandler(value = ConstraintViolationException.class)
public CommonResult constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException ex) {
logger.info("[constraintViolationExceptionHandler]", ex);
// TODO 芋艿,后续要想一个更好的方式。
// 拼接详细报错
StringBuilder detailMessage = new StringBuilder("\n\n详细错误如下:");
ex.getConstraintViolations().forEach(constraintViolation -> detailMessage.append("\n").append(constraintViolation.getMessage()));
return CommonResult.error(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getMessage()
+ detailMessage.toString());
return CommonResult.error(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(),
SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getMessage() + detailMessage.toString());
}

// TODO 芋艿,应该还有其它的异常,需要进行翻译
@ResponseBody
@ExceptionHandler(value = Exception.class)
public CommonResult exceptionHandler(HttpServletRequest req, Exception e) {
logger.error("[exceptionHandler]", e);
// 插入异常日志
ExceptionLogAddDTO exceptionLog = new ExceptionLogAddDTO();
ExceptionLogAddRequest exceptionLog = new ExceptionLogAddRequest();
try {
// 增加异常计数 metrics
EXCEPTION_COUNTER.increment();
// 增加异常计数 metrics TODO 暂时去掉
// EXCEPTION_COUNTER.increment();
// 初始化 exceptionLog
initExceptionLog(exceptionLog, req, e);
// 执行插入 exceptionLog
Expand All @@ -93,13 +92,9 @@ public CommonResult exceptionHandler(HttpServletRequest req, Exception e) {
return CommonResult.error(SysErrorCodeEnum.SYS_ERROR.getCode(), SysErrorCodeEnum.SYS_ERROR.getMessage());
}

private void initExceptionLog(ExceptionLogAddDTO exceptionLog, HttpServletRequest request, Exception e) {
// 设置用户编号
exceptionLog.setUserId(MallUtil.getUserId(request));
if (exceptionLog.getUserId() == null) {
exceptionLog.setUserId(AccessLogAddDTO.USER_ID_NULL);
}
exceptionLog.setUserType(MallUtil.getUserType(request));
private void initExceptionLog(ExceptionLogAddRequest exceptionLog, HttpServletRequest request, Exception e) {
// 设置账号编号
exceptionLog.setAccountId(CommonWebUtil.getAccountId(request));
// 设置异常字段
exceptionLog.setExceptionName(e.getClass().getName());
exceptionLog.setExceptionMessage(ExceptionUtil.getMessage(e));
Expand All @@ -124,8 +119,13 @@ private void initExceptionLog(ExceptionLogAddDTO exceptionLog, HttpServletReques
}

@Async
public void addExceptionLog(ExceptionLogAddDTO exceptionLog) {
systemLogService.addExceptionLog(exceptionLog);
public void addExceptionLog(ExceptionLogAddRequest exceptionLog) {
try {
systemLogRPC.addExceptionLog(exceptionLog);
} catch (Throwable th) {
logger.error("[addAccessLog][插入异常日志({}) 发生异常({})", JSON.toJSONString(exceptionLog), ExceptionUtils.getRootCauseMessage(th));
}

}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cn.iocoder.mall.web.handler;
package cn.iocoder.mall.web.core.handler;

import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.web.util.CommonWebUtil;
import cn.iocoder.mall.web.core.util.CommonWebUtil;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
Expand All @@ -18,7 +18,7 @@
* 原因是,GlobalResponseBodyHandler 本质上是 AOP,它不应该改变 Controller 返回的数据结构
*
* 目前,GlobalResponseBodyHandler 的主要作用是,记录 Controller 的返回结果,
* 方便 {@link cn.iocoder.mall.web.interceptor.AccessLogInterceptor} 记录访问日志
* 方便 {@link cn.iocoder.mall.web.core.interceptor.AccessLogInterceptor} 记录访问日志
*/
@ControllerAdvice
public class GlobalResponseBodyHandler implements ResponseBodyAdvice {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package cn.iocoder.mall.web.interceptor;
package cn.iocoder.mall.web.core.interceptor;

import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.util.MallUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.system.rpc.api.SystemLogRPC;
import cn.iocoder.mall.system.rpc.request.system.AccessLogAddRequest;
import cn.iocoder.mall.web.util.CommonWebUtil;
import cn.iocoder.mall.system.rpc.api.systemlog.SystemLogRPC;
import cn.iocoder.mall.system.rpc.request.systemlog.AccessLogAddRequest;
import cn.iocoder.mall.web.core.util.CommonWebUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.dubbo.config.annotation.Reference;
Expand Down Expand Up @@ -55,7 +55,7 @@ public void afterCompletion(HttpServletRequest request, HttpServletResponse resp
}

private void initAccessLog(AccessLogAddRequest accessLog, HttpServletRequest request) {
// 设置用户编号
// 设置账号编号
accessLog.setAccountId(CommonWebUtil.getAccountId(request));
// 设置访问结果
CommonResult result = CommonWebUtil.getCommonResult(request);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cn.iocoder.mall.web.util;
package cn.iocoder.mall.web.core.util;

import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.web.constant.CommonMallConstants;
import cn.iocoder.mall.web.core.constant.CommonMallConstants;

import javax.servlet.ServletRequest;
import java.util.Date;
Expand Down
Loading

0 comments on commit eec8f08

Please sign in to comment.