浏览代码

:sparkles: 添加新特性。@Inner 内部调用校验

冷冷 6 年之前
父节点
当前提交
444ccb4bd1
共有 17 个文件被更改,包括 169 次插入40 次删除
  1. 2 2
      pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java
  2. 3 0
      pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/LogAutoConfiguration.java
  3. 2 1
      pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/aspect/SysLogAspect.java
  4. 2 1
      pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/event/SysLogListener.java
  5. 46 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/annotation/Inner.java
  6. 11 5
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/GlobalExceptionHandlerResolver.java
  7. 56 0
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxSecurityInnerAspect.java
  8. 1 1
      pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsServiceImpl.java
  9. 2 2
      pigx-config/src/main/resources/config/pigx-upms-biz-dev.yml
  10. 5 2
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteLogService.java
  11. 3 1
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteUserService.java
  12. 2 1
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteLogServiceFallbackImpl.java
  13. 2 1
      pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java
  14. 3 1
      pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/LogController.java
  15. 2 0
      pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSocialDetailsController.java
  16. 25 21
      pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/UserController.java
  17. 2 1
      pigx-visual/pigx-sso-client-demo/src/main/java/com/pig4cloud/pigx/sso/PigxSsoClientDemoApplication.java

+ 2 - 2
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java

@@ -31,9 +31,9 @@ import java.io.Serializable;
  * @param <T>
  * @author lengleng
  */
-@ToString
-@Accessors(chain=true)
 @Builder
+@ToString
+@Accessors(chain = true)
 @AllArgsConstructor
 public class R<T> implements Serializable {
 	private static final long serialVersionUID = 1L;

+ 3 - 0
pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/LogAutoConfiguration.java

@@ -26,12 +26,15 @@ import lombok.AllArgsConstructor;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
 
 /**
  * @author lengleng
  * @date 2018/6/28
+ * <p>
  * 日志自动配置
  */
+@EnableAsync
 @Configuration
 @AllArgsConstructor
 @ConditionalOnWebApplication

+ 2 - 1
pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/aspect/SysLogAspect.java

@@ -27,14 +27,15 @@ import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
 
 /**
  * 操作日志使用spring event异步入库
  *
  * @author L.cm
  */
-@Aspect
 @Slf4j
+@Aspect
 public class SysLogAspect {
 
 	@Around("@annotation(sysLog)")

+ 2 - 1
pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/event/SysLogListener.java

@@ -21,6 +21,7 @@ package com.pig4cloud.pigx.common.log.event;
 
 import com.pig4cloud.pigx.admin.api.entity.SysLog;
 import com.pig4cloud.pigx.admin.api.feign.RemoteLogService;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.event.EventListener;
@@ -42,6 +43,6 @@ public class SysLogListener {
 	@EventListener(SysLogEvent.class)
 	public void saveSysLog(SysLogEvent event) {
 		SysLog sysLog = (SysLog) event.getSource();
-		remoteLogService.saveLog(sysLog);
+		remoteLogService.saveLog(sysLog, SecurityConstants.FROM_IN);
 	}
 }

+ 46 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/annotation/Inner.java

@@ -0,0 +1,46 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.security.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author lengleng
+ * @date 2018/11/26
+ * <p>
+ * 服务调用不鉴权注解
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Inner {
+
+	/**
+	 * 是否AOP统一处理
+	 *
+	 * @return false, true
+	 */
+	boolean value() default true;
+
+	/**
+	 * 需要特殊判空的字段(预留)
+	 *
+	 * @return {}
+	 */
+	String[] field() default {};
+}

+ 11 - 5
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/GlobalExceptionHandlerResolver.java

@@ -19,10 +19,10 @@ package com.pig4cloud.pigx.common.security.component;
 
 import com.pig4cloud.pigx.common.core.constant.CommonConstant;
 import com.pig4cloud.pigx.common.core.util.R;
-import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.core.SpringSecurityMessageSource;
 import org.springframework.validation.BindException;
 import org.springframework.validation.FieldError;
 import org.springframework.web.bind.MethodArgumentNotValidException;
@@ -51,7 +51,10 @@ public class GlobalExceptionHandlerResolver {
 	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
 	public R handleGlobalException(Exception e) {
 		log.error("全局异常信息 ex={}", e.getMessage(), e);
-		return new R<>(e);
+		return R.builder()
+			.msg(e.getLocalizedMessage())
+			.code(CommonConstant.FAIL)
+			.build();
 	}
 
 	/**
@@ -63,9 +66,12 @@ public class GlobalExceptionHandlerResolver {
 	@ExceptionHandler(AccessDeniedException.class)
 	@ResponseStatus(HttpStatus.FORBIDDEN)
 	public R handleAccessDeniedException(AccessDeniedException e) {
-		log.error("拒绝授权异常信息 ex={}",e.getLocalizedMessage(),e);
+		String msg = SpringSecurityMessageSource.getAccessor()
+			.getMessage("AbstractAccessDecisionManager.accessDenied"
+				, e.getMessage());
+		log.error("拒绝授权异常信息 ex={}", msg, e);
 		return R.builder()
-			.msg(e.getLocalizedMessage())
+			.msg(msg)
 			.code(CommonConstant.FAIL)
 			.build();
 	}
@@ -80,7 +86,7 @@ public class GlobalExceptionHandlerResolver {
 	@ResponseStatus(HttpStatus.BAD_REQUEST)
 	public R handleBodyValidException(MethodArgumentNotValidException exception) {
 		List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
-		log.error("参数绑定异常,ex = {}",fieldErrors.get(0).getDefaultMessage());
+		log.error("参数绑定异常,ex = {}", fieldErrors.get(0).getDefaultMessage());
 		return R.builder()
 			.msg(fieldErrors.get(0).getDefaultMessage())
 			.code(CommonConstant.FAIL)

+ 56 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxSecurityInnerAspect.java

@@ -0,0 +1,56 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.security.component;
+
+import cn.hutool.core.util.StrUtil;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.security.annotation.Inner;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author lengleng
+ * @date 2018/11/26
+ * <p>
+ * 服务间接口不鉴权处理逻辑
+ */
+@Slf4j
+@Aspect
+@Component
+@AllArgsConstructor
+public class PigxSecurityInnerAspect {
+	private final HttpServletRequest request;
+
+	@Around("@annotation(inner)")
+	public Object around(ProceedingJoinPoint point, Inner inner) throws Throwable {
+		String header = request.getHeader(SecurityConstants.FROM);
+		if (inner.value() && !StrUtil.equals(SecurityConstants.FROM_IN, header)) {
+			log.warn("访问接口 {} 没有权限", point.getSignature().getName());
+			throw new AccessDeniedException("Access is denied");
+		}
+		return point.proceed();
+	}
+
+}

+ 1 - 1
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsServiceImpl.java

@@ -72,7 +72,7 @@ public class PigxUserDetailsServiceImpl implements PigxUserDetailsService {
 	 */
 	@Override
 	public UserDetails loadUserBySocial(String inStr) throws UsernameNotFoundException {
-		return getUserDetails(remoteUserService.social(inStr));
+		return getUserDetails(remoteUserService.social(inStr, SecurityConstants.FROM_IN));
 	}
 
 	/**

+ 2 - 2
pigx-config/src/main/resources/config/pigx-upms-biz-dev.yml

@@ -10,9 +10,9 @@ security:
         - '/actuator/**'
         - '/v2/api-docs'
         - '/user/info/*'
-        - '/social/info/**'
+        - '/social/info/*'
         - '/mobile/*'
-        - '/log/**'
+        - '/log/save'
 
 # 数据源
 spring:

+ 5 - 2
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteLogService.java

@@ -21,11 +21,13 @@ package com.pig4cloud.pigx.admin.api.feign;
 
 import com.pig4cloud.pigx.admin.api.entity.SysLog;
 import com.pig4cloud.pigx.admin.api.feign.factory.RemoteLogServiceFallbackFactory;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
 import com.pig4cloud.pigx.common.core.constant.ServiceNameConstant;
 import com.pig4cloud.pigx.common.core.util.R;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
 
 /**
  * @author lengleng
@@ -37,8 +39,9 @@ public interface RemoteLogService {
 	 * 保存日志
 	 *
 	 * @param sysLog 日志实体
+	 * @param from   是否内部调用
 	 * @return succes、false
 	 */
-	@PostMapping("/log")
-	R<Boolean> saveLog(@RequestBody SysLog sysLog);
+	@PostMapping("/log/save")
+	R<Boolean> saveLog(@RequestBody SysLog sysLog, @RequestHeader(SecurityConstants.FROM) String from);
 }

+ 3 - 1
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteUserService.java

@@ -53,10 +53,12 @@ public interface RemoteUserService {
 	 * 通过社交账号或手机号查询用户、角色信息
 	 *
 	 * @param inStr appid@code
+	 * @param from  调用标志
 	 * @return
 	 */
 	@GetMapping("/social/info/{inStr}")
-	R<UserInfo> social(@PathVariable("inStr") String inStr);
+	R<UserInfo> social(@PathVariable("inStr") String inStr
+		, @RequestHeader(SecurityConstants.FROM) String from);
 
 	/**
 	 * 查询上级部门的用户信息

+ 2 - 1
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteLogServiceFallbackImpl.java

@@ -40,10 +40,11 @@ public class RemoteLogServiceFallbackImpl implements RemoteLogService {
 	 * 保存日志
 	 *
 	 * @param sysLog
+	 * @param from
 	 * @return R
 	 */
 	@Override
-	public R<Boolean> saveLog(SysLog sysLog) {
+	public R<Boolean> saveLog(SysLog sysLog, String from) {
 		log.error("feign 插入日志失败", cause);
 		return null;
 	}

+ 2 - 1
pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java

@@ -56,10 +56,11 @@ public class RemoteUserServiceFallbackImpl implements RemoteUserService {
 	 * 通过社交账号查询用户、角色信息
 	 *
 	 * @param inStr appid@code
+	 * @param from  内外标志
 	 * @return
 	 */
 	@Override
-	public R<UserInfo> social(String inStr) {
+	public R<UserInfo> social(String inStr, String from) {
 		log.error("feign 查询用户信息失败:{}", inStr, cause);
 		return null;
 	}

+ 3 - 1
pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/LogController.java

@@ -26,6 +26,7 @@ import com.pig4cloud.pigx.admin.api.entity.SysLog;
 import com.pig4cloud.pigx.admin.api.vo.PreLogVo;
 import com.pig4cloud.pigx.admin.service.SysLogService;
 import com.pig4cloud.pigx.common.core.util.R;
+import com.pig4cloud.pigx.common.security.annotation.Inner;
 import io.swagger.annotations.Api;
 import lombok.AllArgsConstructor;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -79,7 +80,8 @@ public class LogController {
 	 * @param sysLog 日志实体
 	 * @return success/false
 	 */
-	@PostMapping
+	@Inner
+	@PostMapping("/save")
 	public R save(@Valid @RequestBody SysLog sysLog) {
 		return new R<>(sysLogService.save(sysLog));
 	}

+ 2 - 0
pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSocialDetailsController.java

@@ -23,6 +23,7 @@ import com.pig4cloud.pigx.admin.api.entity.SysSocialDetails;
 import com.pig4cloud.pigx.admin.service.SysSocialDetailsService;
 import com.pig4cloud.pigx.common.core.util.R;
 import com.pig4cloud.pigx.common.log.annotation.SysLog;
+import com.pig4cloud.pigx.common.security.annotation.Inner;
 import io.swagger.annotations.Api;
 import lombok.AllArgsConstructor;
 import org.springframework.web.bind.annotation.*;
@@ -111,6 +112,7 @@ public class SysSocialDetailsController {
 	 * @param inStr appid@code
 	 * @return
 	 */
+	@Inner
 	@GetMapping("/info/{inStr}")
 	public R getUserInfo(@PathVariable String inStr) {
 		return new R<>(sysSocialDetailsService.getUserInfo(inStr));

+ 25 - 21
pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/UserController.java

@@ -19,16 +19,15 @@
 
 package com.pig4cloud.pigx.admin.controller;
 
-import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.pig4cloud.pigx.admin.api.dto.UserDTO;
 import com.pig4cloud.pigx.admin.api.entity.SysUser;
 import com.pig4cloud.pigx.admin.service.SysUserService;
-import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
 import com.pig4cloud.pigx.common.core.util.R;
 import com.pig4cloud.pigx.common.log.annotation.SysLog;
+import com.pig4cloud.pigx.common.security.annotation.Inner;
 import com.pig4cloud.pigx.common.security.util.SecurityUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
@@ -51,34 +50,39 @@ public class UserController {
 	private final SysUserService userService;
 
 	/**
-	 * 获取当前用户信息(角色、权限)
-	 * 并且异步初始化用户部门信息
+	 * 获取当前用户全部信息
 	 *
-	 * @param from     请求标志,该接口会被 auth、 前端调用
-	 * @param username 用户名
-	 * @return 用户名
+	 * @return 用户信息
 	 */
-	@GetMapping(value = {"/info", "/info/{username}"})
-	public R user(@PathVariable(required = false) String username,
-				  @RequestHeader(required = false) String from) {
-		// 查询用户不为空时判断是不是内部请求
-		if (StrUtil.isNotBlank(username) && !StrUtil.equals(SecurityConstants.FROM_IN, from)) {
-			return new R<>(null, "error");
-		}
-		//为空时查询当前用户
-		if (StrUtil.isBlank(username)) {
-			username = SecurityUtils.getUser().getUsername();
-		}
+	@GetMapping(value = {"/info"})
+	public R info() {
+		String username = SecurityUtils.getUser().getUsername();
 		SysUser sysUser = userService.getOne(Wrappers.<SysUser>query()
 			.lambda().eq(SysUser::getUsername, username));
 		if (sysUser == null) {
-			return new R<>();
+			return new R<>(Boolean.FALSE, "获取当前用户信息失败");
 		}
 		return new R<>(userService.findUserInfo(sysUser));
 	}
 
 	/**
-	 * 通过ID查询当前用户信息
+	 * 获取指定用户全部信息
+	 *
+	 * @return 用户信息
+	 */
+	@Inner
+	@GetMapping("/info/{username}")
+	public R info(@PathVariable String username) {
+		SysUser user = userService.getOne(Wrappers.<SysUser>query()
+			.lambda().eq(SysUser::getUsername, username));
+		if (user == null) {
+			return new R<>(Boolean.FALSE, String.format("用户信息为空 %s", username));
+		}
+		return new R<>(userService.findUserInfo(user));
+	}
+
+	/**
+	 * 通过ID查询用户信息
 	 *
 	 * @param id ID
 	 * @return 用户信息
@@ -169,7 +173,7 @@ public class UserController {
 
 	/**
 	 * @param username 用户名称
-	 * @return
+	 * @return 上级部门用户列表
 	 */
 	@GetMapping("/ancestor/{username}")
 	public R listAncestorUsers(@PathVariable String username) {

+ 2 - 1
pigx-visual/pigx-sso-client-demo/src/main/java/com/pig4cloud/pigx/sso/PigxSsoClientDemoApplication.java

@@ -26,7 +26,8 @@ import org.springframework.cloud.client.SpringCloudApplication;
  * @date 2018年11月15日17:06:26
  * <p>
  * 单点登录客户端
- * 访问:http://localhost:4040/sso1/
+ * 1. 启动实例访问:http://localhost:4040/sso1/ 提示登录,然后获取到用户信息
+ * 2. 再启动一个实例: http://localhost:4040/sso1/ 不需要登录即可获取当前用户信息
  */
 @EnableOAuth2Sso
 @SpringCloudApplication