程序员蜗牛
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