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

This commit is contained in:
冷冷 committed 2018-11-27 10:49:30 +08:00
1 parent d32090bf51
commit 444ccb4bd1
17 files changed
+169 -40

No files matched your search

@@ -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;
@@ -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
@@ -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)")
@@ -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);
}
}
@@ -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 {};
}
@@ -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)
@@ -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();
}
}
@@ -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));
}
/**
@@ -10,9 +10,9 @@ security:
- '/actuator/**'
- '/v2/api-docs'
- '/user/info/*'
- '/social/info/**'
- '/social/info/*'
- '/mobile/*'
- '/log/**'
- '/log/save'
# 数据源
spring:
@@ -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);
}
@@ -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);
/**
* 查询上级部门的用户信息
@@ -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;
}
@@ -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;
}
@@ -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));
}
@@ -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));
@@ -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) {
@@ -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