程序员蜗牛
1 year ago
13 changed files with 548 additions and 0 deletions
@ -0,0 +1,33 @@ |
|||||
|
HELP.md |
||||
|
target/ |
||||
|
!.mvn/wrapper/maven-wrapper.jar |
||||
|
!**/src/main/**/target/ |
||||
|
!**/src/test/**/target/ |
||||
|
|
||||
|
### STS ### |
||||
|
.apt_generated |
||||
|
.classpath |
||||
|
.factorypath |
||||
|
.project |
||||
|
.settings |
||||
|
.springBeans |
||||
|
.sts4-cache |
||||
|
|
||||
|
### IntelliJ IDEA ### |
||||
|
.idea |
||||
|
*.iws |
||||
|
*.iml |
||||
|
*.ipr |
||||
|
|
||||
|
### NetBeans ### |
||||
|
/nbproject/private/ |
||||
|
/nbbuild/ |
||||
|
/dist/ |
||||
|
/nbdist/ |
||||
|
/.nb-gradle/ |
||||
|
build/ |
||||
|
!**/src/main/**/build/ |
||||
|
!**/src/test/**/build/ |
||||
|
|
||||
|
### VS Code ### |
||||
|
.vscode/ |
@ -0,0 +1,98 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<groupId>com.springboot.sample</groupId> |
||||
|
<artifactId>sample</artifactId> |
||||
|
<version>0.0.1-SNAPSHOT</version> |
||||
|
<name>sample</name> |
||||
|
<description>Spring Boot Sample</description> |
||||
|
<packaging>jar</packaging> |
||||
|
|
||||
|
<properties> |
||||
|
<java.version>1.8</java.version> |
||||
|
<spring.boot.version>2.1.15.RELEASE</spring.boot.version> |
||||
|
<spring.cloud.alibaba.version>2.1.2.RELEASE</spring.cloud.alibaba.version> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencyManagement> |
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-dependencies</artifactId> |
||||
|
<version>${spring.boot.version}</version> |
||||
|
<type>pom</type> |
||||
|
<scope>import</scope> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||
|
<version>${spring.boot.version}</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-test</artifactId> |
||||
|
<version>${spring.boot.version}</version> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
</dependencyManagement> |
||||
|
<dependencies> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-test</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
<!--热部署--> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-devtools</artifactId> |
||||
|
<scope>runtime</scope> |
||||
|
<optional>true</optional> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.aspectj</groupId> |
||||
|
<artifactId>aspectjrt</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>commons-lang</groupId> |
||||
|
<artifactId>commons-lang</artifactId> |
||||
|
<version>2.6</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>cn.hutool</groupId> |
||||
|
<artifactId>hutool-all</artifactId> |
||||
|
<version>5.8.16</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.aspectj</groupId> |
||||
|
<artifactId>aspectjweaver</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.projectlombok</groupId> |
||||
|
<artifactId>lombok</artifactId> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
|
||||
|
<build> |
||||
|
<plugins> |
||||
|
<plugin> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
|
</plugin> |
||||
|
</plugins> |
||||
|
</build> |
||||
|
|
||||
|
</project> |
@ -0,0 +1,15 @@ |
|||||
|
package com.springboot.sample; |
||||
|
|
||||
|
|
||||
|
import org.springframework.boot.SpringApplication; |
||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
|
||||
|
|
||||
|
@SpringBootApplication |
||||
|
public class SampleApplication { |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
SpringApplication.run(SampleApplication.class, args); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,91 @@ |
|||||
|
package com.springboot.sample.utils; |
||||
|
|
||||
|
import org.springframework.core.BridgeMethodResolver; |
||||
|
import org.springframework.core.DefaultParameterNameDiscoverer; |
||||
|
import org.springframework.core.MethodParameter; |
||||
|
import org.springframework.core.ParameterNameDiscoverer; |
||||
|
import org.springframework.core.annotation.AnnotatedElementUtils; |
||||
|
import org.springframework.core.annotation.SynthesizingMethodParameter; |
||||
|
import org.springframework.web.method.HandlerMethod; |
||||
|
import java.lang.annotation.Annotation; |
||||
|
import java.lang.reflect.Constructor; |
||||
|
import java.lang.reflect.Method; |
||||
|
|
||||
|
/** |
||||
|
* 类工具类 |
||||
|
*/ |
||||
|
public class ClassUtil extends org.springframework.util.ClassUtils { |
||||
|
|
||||
|
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer(); |
||||
|
|
||||
|
/** |
||||
|
* 获取方法参数信息 |
||||
|
* |
||||
|
* @param constructor 构造器 |
||||
|
* @param parameterIndex 参数序号 |
||||
|
* @return {MethodParameter} |
||||
|
*/ |
||||
|
public static MethodParameter getMethodParameter(Constructor<?> constructor, int parameterIndex) { |
||||
|
MethodParameter methodParameter = new SynthesizingMethodParameter(constructor, parameterIndex); |
||||
|
methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER); |
||||
|
return methodParameter; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取方法参数信息 |
||||
|
* |
||||
|
* @param method 方法 |
||||
|
* @param parameterIndex 参数序号 |
||||
|
* @return {MethodParameter} |
||||
|
*/ |
||||
|
public static MethodParameter getMethodParameter(Method method, int parameterIndex) { |
||||
|
MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex); |
||||
|
methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER); |
||||
|
return methodParameter; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取Annotation |
||||
|
* |
||||
|
* @param method Method |
||||
|
* @param annotationType 注解类 |
||||
|
* @param <A> 泛型标记 |
||||
|
* @return {Annotation} |
||||
|
*/ |
||||
|
public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) { |
||||
|
Class<?> targetClass = method.getDeclaringClass(); |
||||
|
// The method may be on an interface, but we need attributes from the target class.
|
||||
|
// If the target class is null, the method will be unchanged.
|
||||
|
Method specificMethod = ClassUtil.getMostSpecificMethod(method, targetClass); |
||||
|
// If we are dealing with method with generic parameters, find the original method.
|
||||
|
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); |
||||
|
// 先找方法,再找方法上的类
|
||||
|
A annotation = AnnotatedElementUtils.findMergedAnnotation(specificMethod, annotationType); |
||||
|
; |
||||
|
if (null != annotation) { |
||||
|
return annotation; |
||||
|
} |
||||
|
// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类
|
||||
|
return AnnotatedElementUtils.findMergedAnnotation(specificMethod.getDeclaringClass(), annotationType); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取Annotation |
||||
|
* |
||||
|
* @param handlerMethod HandlerMethod |
||||
|
* @param annotationType 注解类 |
||||
|
* @param <A> 泛型标记 |
||||
|
* @return {Annotation} |
||||
|
*/ |
||||
|
public static <A extends Annotation> A getAnnotation(HandlerMethod handlerMethod, Class<A> annotationType) { |
||||
|
// 先找方法,再找方法上的类
|
||||
|
A annotation = handlerMethod.getMethodAnnotation(annotationType); |
||||
|
if (null != annotation) { |
||||
|
return annotation; |
||||
|
} |
||||
|
// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类
|
||||
|
Class<?> beanType = handlerMethod.getBeanType(); |
||||
|
return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,85 @@ |
|||||
|
package com.springboot.sample.www; |
||||
|
|
||||
|
import com.springboot.sample.utils.ClassUtil; |
||||
|
import org.apache.commons.lang.StringUtils; |
||||
|
import org.aspectj.lang.ProceedingJoinPoint; |
||||
|
import org.aspectj.lang.annotation.Around; |
||||
|
import org.aspectj.lang.annotation.Aspect; |
||||
|
import org.aspectj.lang.annotation.Pointcut; |
||||
|
import org.aspectj.lang.reflect.MethodSignature; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.context.ApplicationContext; |
||||
|
import org.springframework.context.expression.BeanFactoryResolver; |
||||
|
import org.springframework.core.MethodParameter; |
||||
|
import org.springframework.expression.Expression; |
||||
|
import org.springframework.expression.ExpressionParser; |
||||
|
import org.springframework.expression.spel.standard.SpelExpressionParser; |
||||
|
import org.springframework.expression.spel.support.StandardEvaluationContext; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.lang.reflect.Method; |
||||
|
|
||||
|
@Aspect |
||||
|
@Component |
||||
|
public class AopService { |
||||
|
|
||||
|
@Autowired |
||||
|
private ApplicationContext applicationContext; |
||||
|
|
||||
|
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); |
||||
|
|
||||
|
//切点
|
||||
|
@Pointcut("@annotation(com.springboot.sample.www.PreAuth) || @within(com.springboot.sample.www.PreAuth)") |
||||
|
private void cutMethod() { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@Around("cutMethod()") |
||||
|
public Object preAuth(ProceedingJoinPoint point) throws Throwable { |
||||
|
if (handleAuth(point)) { |
||||
|
return point.proceed(); |
||||
|
} |
||||
|
throw new SecureException("200"); |
||||
|
} |
||||
|
|
||||
|
private boolean handleAuth(ProceedingJoinPoint point) { |
||||
|
MethodSignature ms = point.getSignature() instanceof MethodSignature ? (MethodSignature) point.getSignature() : null; |
||||
|
Method method = ms.getMethod(); |
||||
|
// 读取权限注解,优先方法上,没有则读取类
|
||||
|
PreAuth preAuth = ClassUtil.getAnnotation(method, PreAuth.class);//hasRole('admin') -》 hasRole(入参)
|
||||
|
// 判断表达式
|
||||
|
String condition = preAuth.value(); |
||||
|
if (StringUtils.isNotBlank(condition)) { |
||||
|
Expression expression = EXPRESSION_PARSER.parseExpression(condition); |
||||
|
// 方法参数值
|
||||
|
Object[] args = point.getArgs(); |
||||
|
StandardEvaluationContext context = getEvaluationContext(method, args); |
||||
|
//获取解析计算的结果
|
||||
|
return expression.getValue(context, Boolean.class); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取方法上的参数 |
||||
|
* |
||||
|
* @param method 方法 |
||||
|
* @param args 变量 |
||||
|
* @return {SimpleEvaluationContext} |
||||
|
*/ |
||||
|
private StandardEvaluationContext getEvaluationContext(Method method, Object[] args) { |
||||
|
// 初始化Spel表达式上下文,并设置 AuthFun
|
||||
|
StandardEvaluationContext context = new StandardEvaluationContext(new AuthFun()); |
||||
|
// 设置表达式支持spring bean
|
||||
|
context.setBeanResolver(new BeanFactoryResolver(applicationContext)); |
||||
|
for (int i = 0; i < args.length; i++) { |
||||
|
// 读取方法参数
|
||||
|
MethodParameter methodParam = ClassUtil.getMethodParameter(method, i); |
||||
|
// 设置方法 参数名和值 为spel变量
|
||||
|
context.setVariable(methodParam.getParameterName(), args[i]); |
||||
|
} |
||||
|
return context; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,124 @@ |
|||||
|
package com.springboot.sample.www; |
||||
|
|
||||
|
import cn.hutool.core.collection.CollectionUtil; |
||||
|
import org.apache.commons.lang.StringUtils; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
import java.util.List; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
public class AuthFun { |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 判断角色是否具有接口权限 |
||||
|
* |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean permissionAll() { |
||||
|
//TODO
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断角色是否具有接口权限 |
||||
|
* |
||||
|
* @param permission 权限编号,对应菜单的MENU_CODE |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean hasPermission(String permission) { |
||||
|
//TODO
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 放行所有请求 |
||||
|
* |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean permitAll() { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 只有超管角色才可访问 |
||||
|
* |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean denyAll() { |
||||
|
return hasRole(RoleConstant.ADMIN); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 是否已授权 |
||||
|
* |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean hasAuth() { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 是否有时间授权 |
||||
|
* |
||||
|
* @param start 开始时间 |
||||
|
* @param end 结束时间 |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean hasTimeAuth(Integer start, Integer end) { |
||||
|
return true; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否有该角色权限 |
||||
|
* |
||||
|
* @param role 单角色 |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean hasRole(String role) { |
||||
|
return hasAnyRole(role); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否具有所有角色权限 |
||||
|
* |
||||
|
* @param role 角色集合 |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean hasAllRole(String... role) { |
||||
|
for (String r : role) { |
||||
|
if (!hasRole(r)) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否有该角色权限 |
||||
|
* @param role 角色集合 |
||||
|
* @return {boolean} |
||||
|
*/ |
||||
|
public boolean hasAnyRole(String... role) { |
||||
|
//获取当前登录用户 这边模拟当前用户是管理员
|
||||
|
UserVO user = new UserVO(); |
||||
|
user.setRoleName("admin,projectManager"); |
||||
|
|
||||
|
String userRole = user.getRoleName(); |
||||
|
if (StringUtils.isBlank(userRole)) { |
||||
|
return false; |
||||
|
} |
||||
|
List<String> roles = Arrays.stream(userRole.split(",")).collect(Collectors.toList()); |
||||
|
for (String r : role) { |
||||
|
if (CollectionUtil.contains(roles, r)) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package com.springboot.sample.www; |
||||
|
|
||||
|
|
||||
|
import java.lang.annotation.ElementType; |
||||
|
import java.lang.annotation.Retention; |
||||
|
import java.lang.annotation.RetentionPolicy; |
||||
|
import java.lang.annotation.Target; |
||||
|
|
||||
|
@Target({ElementType.METHOD, ElementType.TYPE}) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
public @interface PreAuth { |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* permissionAll()-----只要配置了角色就可以访问 |
||||
|
* hasPermission("MENU.QUERY")-----有MENU.QUERY操作权限的角色可以访问 |
||||
|
* permitAll()-----放行所有请求 |
||||
|
* denyAll()-----只有超级管理员角色才可访问 |
||||
|
* hasAuth()-----只有登录后才可访问 |
||||
|
* hasTimeAuth(1,10)-----只有在1-10点间访问 |
||||
|
* hasRole(‘管理员’)-----具有管理员角色的人才能访问 |
||||
|
* hasAllRole(‘管理员’,'总工程师')-----同时具有管理员、总工程师角色的人才能访问 |
||||
|
* Spring el |
||||
|
* |
||||
|
*/ |
||||
|
String value(); |
||||
|
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package com.springboot.sample.www; |
||||
|
|
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/pre") |
||||
|
@Slf4j |
||||
|
//@PreAuth(value = "hasRole('admin')")
|
||||
|
public class PreController { |
||||
|
|
||||
|
/** |
||||
|
* SpringBoot中引入SpEL,优雅搞定复杂权限控制! |
||||
|
* @param userId |
||||
|
* @return |
||||
|
*/ |
||||
|
@GetMapping("/{userId}") |
||||
|
@ResponseBody |
||||
|
@PreAuth(value = "hasRole('admin')") |
||||
|
public String getUser(@PathVariable String userId) { |
||||
|
log.info("hahaha"); |
||||
|
return userId; |
||||
|
} |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
package com.springboot.sample.www; |
||||
|
|
||||
|
|
||||
|
public enum ResultCode { |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
package com.springboot.sample.www; |
||||
|
public class RoleConstant { |
||||
|
|
||||
|
|
||||
|
public static final String ADMIN = "admin"; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
package com.springboot.sample.www; |
||||
|
|
||||
|
public class SecureException extends RuntimeException { |
||||
|
|
||||
|
private String code; |
||||
|
|
||||
|
public SecureException(String code) { |
||||
|
this.code = code; |
||||
|
} |
||||
|
|
||||
|
public SecureException() { |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package com.springboot.sample.www; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class UserVO { |
||||
|
private String userId; |
||||
|
|
||||
|
// 拥有的角色名
|
||||
|
private String roleName; |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
server: |
||||
|
port: 8080 |
||||
|
|
||||
|
spring: |
||||
|
jackson: |
||||
|
date-format: yyyy-MM-dd HH:mm:ss |
||||
|
time-zone: GMT+8 |
||||
|
serialization: |
||||
|
write-dates-as-timestamps: false |
||||
|
|
Loading…
Reference in new issue