- 后端:User 模块,接入统一的 OAuth2 服务
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user