增加 auth 授权相关处理(未完成)
This commit is contained in:
@@ -6,7 +6,6 @@ import cn.iocoder.mall.web.core.constant.CommonMallConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -22,16 +21,22 @@ public class CommonSecurityAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
// ========== 拦截器相关 ==========
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AccountAuthInterceptor.class)
|
||||
public AccountAuthInterceptor accountAuthInterceptor() {
|
||||
return new AccountAuthInterceptor();
|
||||
public AccountAuthInterceptor adminAccountAuthInterceptor() {
|
||||
return new AccountAuthInterceptor(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AccountAuthInterceptor userAccountAuthInterceptor() {
|
||||
return new AccountAuthInterceptor(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// AccountAuthInterceptor 拦截器
|
||||
registry.addInterceptor(this.accountAuthInterceptor())
|
||||
.addPathPatterns(CommonMallConstants.ROOT_PATH_ADMIN + "/**", CommonMallConstants.ROOT_PATH_USER + "/**");
|
||||
registry.addInterceptor(this.userAccountAuthInterceptor())
|
||||
.addPathPatterns(CommonMallConstants.ROOT_PATH_USER + "/**");
|
||||
registry.addInterceptor(this.adminAccountAuthInterceptor())
|
||||
.addPathPatterns(CommonMallConstants.ROOT_PATH_ADMIN + "/**");
|
||||
logger.info("[addInterceptors][加载 AccountAuthInterceptor 拦截器完成]");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,16 @@ package cn.iocoder.mall.security.core.annotation;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 要求用户登录注解。通过将该注解添加到 Controller 上,会自动校验用户是否登陆。
|
||||
* 要求用户认证(登陆)注解。通过将该注解添加到 Controller 上,会自动校验用户是否登陆。
|
||||
*
|
||||
* 默认请求下,用户访问的 API 接口,无需登陆。主要的考虑是,
|
||||
* 1. 需要用户登陆的接口,本身会获取在线用户的编号。如果不添加 @RequiresLogin 注解就会报错。
|
||||
* 2. 大多数情况下,用户的 API 接口无需登陆。
|
||||
*
|
||||
* ps:同样适用于管理员 Admin
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD}) // 暂时不支持 ElementType.TYPE ,因为没有场景
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RequiresLogin {
|
||||
public @interface RequiresAuthenticate {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cn.iocoder.mall.security.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 通过将该注解添加到 Controller 的方法上,声明无需进行登陆
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD}) // 暂时不支持 ElementType.TYPE ,因为没有场景
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RequiresNone {
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import java.lang.annotation.*;
|
||||
* 参考 Shiro @RequiresPermissions 设计 http://shiro.apache.org/static/1.3.2/apidocs/org/apache/shiro/authz/annotation/RequiresPermissions.html
|
||||
*
|
||||
* 通过将该注解添加到 Controller 的方法上,进行授权鉴定
|
||||
*
|
||||
* ps:目前暂时只有管理员 Admin 使用到
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD}) // 暂时不支持 ElementType.TYPE ,因为没有场景
|
||||
|
||||
@@ -3,10 +3,8 @@ package cn.iocoder.mall.security.core.context;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Security 上下文
|
||||
* Admin Security 上下文
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@@ -20,9 +18,5 @@ public class AdminSecurityContext {
|
||||
* 管理员账号
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* 拥有的角色编号
|
||||
*/
|
||||
private Set<Integer> roleIds;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package cn.iocoder.mall.security.core.interceptor;
|
||||
|
||||
import cn.iocoder.common.framework.util.CollectionUtil;
|
||||
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.security.core.annotation.RequiresAuthenticate;
|
||||
import cn.iocoder.mall.security.core.annotation.RequiresNone;
|
||||
import cn.iocoder.mall.security.core.annotation.RequiresPermissions;
|
||||
import cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum;
|
||||
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;
|
||||
@@ -11,6 +16,7 @@ import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -23,12 +29,36 @@ public class AccountAuthInterceptor extends HandlerInterceptorAdapter {
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.OAuth2RPC.version}")
|
||||
private OAuth2RPC oauth2RPC;
|
||||
|
||||
|
||||
/**
|
||||
* 是否默认要求认证
|
||||
*
|
||||
* 针对 /users/** 接口,一般默认不要求认证,因为面向用户的接口,往往不需要登陆即可访问
|
||||
* 针对 /admins/** 接口,一般默认要求认证,因为面向管理员的接口,往往是内部需要更严格的安全控制
|
||||
*/
|
||||
private final boolean defaultRequiresAuthenticate;
|
||||
|
||||
public AccountAuthInterceptor(boolean defaultRequiresAuthenticate) {
|
||||
this.defaultRequiresAuthenticate = defaultRequiresAuthenticate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
// 获得访问令牌
|
||||
String accessToken = HttpUtil.obtainAuthorization(request);
|
||||
if (StringUtils.hasText(accessToken)) { // 如果未传递,则不进行认证
|
||||
return true;
|
||||
// 1. 进行认证
|
||||
Integer accountId = this.obtainAccount(request);
|
||||
// 2. 进行鉴权
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
// 判断是否需要认证
|
||||
this.checkAuthenticate(handlerMethod, accountId);
|
||||
// 判断是否需要权限
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Integer obtainAccount(HttpServletRequest request) {
|
||||
String accessToken = HttpUtil.obtainAuthorization(request); // 获得访问令牌
|
||||
if (!StringUtils.hasText(accessToken)) { // 如果未传递,则不进行认证
|
||||
return null;
|
||||
}
|
||||
// 执行认证
|
||||
OAuth2AccessTokenAuthenticateRequest oauth2AccessTokenAuthenticateRequest = new OAuth2AccessTokenAuthenticateRequest()
|
||||
@@ -38,8 +68,35 @@ public class AccountAuthInterceptor extends HandlerInterceptorAdapter {
|
||||
throw ServiceExceptionUtil.exception(oauth2AccessTokenResponseResult);
|
||||
}
|
||||
// 设置账号编号
|
||||
CommonWebUtil.setAccountId(request, oauth2AccessTokenResponseResult.getData().getAccountId());
|
||||
return true;
|
||||
Integer accountId = oauth2AccessTokenResponseResult.getData().getAccountId();
|
||||
CommonWebUtil.setAccountId(request, accountId);
|
||||
return accountId;
|
||||
}
|
||||
|
||||
private void checkAuthenticate(HandlerMethod handlerMethod, Integer accountId) {
|
||||
boolean requiresAuthenticate = defaultRequiresAuthenticate;
|
||||
if (handlerMethod.hasMethodAnnotation(RequiresAuthenticate.class)
|
||||
|| handlerMethod.hasMethodAnnotation(RequiresPermissions.class)) { // 如果需要权限验证,也认为需要认证
|
||||
requiresAuthenticate = true;
|
||||
} else if (handlerMethod.hasMethodAnnotation(RequiresNone.class)) {
|
||||
requiresAuthenticate = false;
|
||||
}
|
||||
if (requiresAuthenticate && accountId == null) {
|
||||
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_NOT_AUTHENTICATE);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPermission(HandlerMethod handlerMethod, Integer accountId) {
|
||||
RequiresPermissions requiresPermissions = handlerMethod.getMethodAnnotation(RequiresPermissions.class);
|
||||
if (requiresPermissions == null) {
|
||||
return;
|
||||
}
|
||||
String[] permissions = requiresPermissions.value();
|
||||
if (CollectionUtil.isEmpty(permissions)) {
|
||||
return;
|
||||
}
|
||||
// 权限验证
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.mall.security.core.interceptor;
|
||||
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 获得 Admin 信息
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.iocoder.mall.security.core.interceptor;
|
||||
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 获得用户信息
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
super.afterCompletion(request, response, handler, ex);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user