- 后端:User 模块,接入统一的 OAuth2 服务

This commit is contained in:
YunaiV
2019-05-17 00:35:42 +08:00
parent be94f29791
commit 68027b9f16
28 changed files with 229 additions and 178 deletions

View File

@@ -1,18 +1,18 @@
package cn.iocoder.mall.user.sdk.context;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* User Security 上下文
*/
@Data
@Accessors(chain = true)
public class UserSecurityContext {
private final Integer userId;
/**
* 用户编号
*/
private Integer userId;
public UserSecurityContext(Integer userId) {
this.userId = userId;
}
public Integer getUserId() {
return userId;
}
}
}

View File

@@ -17,7 +17,7 @@ public class UserSecurityContextHolder {
UserSecurityContext ctx = SECURITY_CONTEXT.get();
// 为空时,设置一个空的进去
if (ctx == null) {
ctx = new UserSecurityContext(null);
ctx = new UserSecurityContext();
SECURITY_CONTEXT.set(ctx);
}
return ctx;

View File

@@ -1,11 +1,14 @@
package cn.iocoder.mall.user.sdk.interceptor;
import cn.iocoder.common.framework.constant.MallConstants;
import cn.iocoder.common.framework.constant.UserTypeEnum;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.util.MallUtil;
import cn.iocoder.mall.user.api.OAuth2Service;
import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.mall.admin.api.OAuth2Service;
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2GetTokenDTO;
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
import cn.iocoder.mall.user.sdk.context.UserSecurityContext;
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
@@ -18,40 +21,55 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 安全拦截器
* User 安全拦截器
*/
@Component
public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
@Reference(validation = "true", version = "${dubbo.provider.OAuth2Service.version:1.0.0}")
@Reference(validation = "true", version = "${dubbo.consumer.OAuth2Service.version:1.0.0}")
private OAuth2Service oauth2Service;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 设置当前访问的用户类型。注意,即使未登陆,我们也认为是用户
MallUtil.setUserType(request, MallConstants.USER_TYPE_USER);
// 校验访问令牌是否正确。若正确,返回授权信息
MallUtil.setUserType(request, UserTypeEnum.USER.getValue());
// 根据 accessToken 获得认证信息,判断是谁
String accessToken = HttpUtil.obtainAuthorization(request);
OAuth2AuthenticationBO authentication = null;
if (accessToken != null) {
authentication = oauth2Service.checkToken(accessToken); // TODO 芋艿,如果访问的地址无需登录,这里也不用抛异常
// 添加到 SecurityContext
UserSecurityContext context = new UserSecurityContext(authentication.getUserId());
UserSecurityContextHolder.setContext(context);
// 同时也记录管理员编号到 AdminAccessLogInterceptor 中。因为:
// AdminAccessLogInterceptor 需要在 AdminSecurityInterceptor 之前执行,这样记录的访问日志才健全
// AdminSecurityInterceptor 执行后,会移除 AdminSecurityContext 信息,这就导致 AdminAccessLogInterceptor 无法获得管理员编号
// 因此,这里需要进行记录
if (authentication.getUserId() != null) {
MallUtil.setUserId(request, authentication.getUserId());
ServiceException serviceException = null;
if (StringUtil.hasText(accessToken)) {
try {
authentication = oauth2Service.getAuthentication(new OAuth2GetTokenDTO().setAccessToken(accessToken)
.setUserType(UserTypeEnum.USER.getValue()));
} catch (ServiceException e) {
serviceException = e;
}
}
// 校验是否需要已授权
// 进行鉴权
HandlerMethod method = (HandlerMethod) handler;
boolean isPermitAll = method.hasMethodAnnotation(PermitAll.class);
if (!isPermitAll && authentication == null) {
throw new ServiceException(-1, "未授权"); // TODO 这里要改下
if (!isPermitAll) { // 如果需要鉴权
if (serviceException != null) { // 认证失败,抛出上面认证失败的 ServiceException 异常
throw serviceException;
}
if (authentication == null) { // 无认证信息,抛出未登陆 ServiceException 异常
throw new ServiceException(AdminErrorCodeEnum.OAUTH2_NOT_LOGIN.getCode(), AdminErrorCodeEnum.OAUTH2_NOT_LOGIN.getMessage());
}
// TODO 芋艿,后续拓展读取用户信息
}
// 鉴权完成,初始化 AdminSecurityContext 上下文
UserSecurityContext context = new UserSecurityContext();
UserSecurityContextHolder.setContext(context);
if (authentication != null) {
context.setUserId(authentication.getUserId());
MallUtil.setUserId(request, authentication.getUserId()); // 记录到 request 中,避免 AdminSecurityContext 后续清理掉后,其它地方需要用到 userId
// TODO 芋艿,后续拓展读取用户信息
}
// 返回成功
return super.preHandle(request, response, handler);
}