Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/main/java/io/qyi/e5/config/security/SecurityAuthenticationHandler.java
#	src/main/java/io/qyi/e5/config/security/SecurityConfig.java
#	src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationProvider.java
#	src/main/java/io/qyi/e5/config/security/filter/LinkTokenAuthenticationFilter.java
This commit is contained in:
LuoYe_MyWork 2020-06-19 17:16:30 +08:00
commit fe77f2d7f2
10 changed files with 211 additions and 22 deletions

21
pom.xml
View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version> <version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>io.qyi</groupId> <groupId>io.qyi</groupId>
@ -35,16 +35,23 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<!-- log4j2 --> <!--排除自带的logging-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--log4j2-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId> <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency> </dependency>
<!-- freemarker 模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--权限管理插件--> <!--权限管理插件-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@ -0,0 +1,65 @@
package io.qyi.e5.config.security;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.Iterator;
/**
* 决策管理器
*
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-06-15 16:11
**/
@Slf4j
@Service
public class MyAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
if (collection == null) {
return;
}
System.out.println(o.toString()); // object is a URL.
log.info("object is a URL. {}", o.toString());
//所请求的资源拥有的权限(一个资源对多个权限)
Iterator<ConfigAttribute> iterator = collection.iterator();
while (iterator.hasNext()) {
ConfigAttribute configAttribute = iterator.next();
//访问所请求资源所需要的权限
String needPermission = configAttribute.getAttribute();
log.info("访问 " + o.toString() + " 需要的权限是:" + needPermission);
if (needPermission == null) {
break;
}
//用户所拥有的权限authentication
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority ga : authorities) {
if (needPermission.equals(ga.getAuthority())) {
return;
}
}
}
//没有权限
throw new AccessDeniedException(" 无权限! ");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}

View File

@ -0,0 +1,68 @@
package io.qyi.e5.config.security;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-06-17 16:25
**/
@Service
public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {
private HashMap<String, Collection<ConfigAttribute>> map =null;
/**
* 加载权限表中所有权限
*/
public void loadResourceDefine(){
map = new HashMap<>();
Collection<ConfigAttribute> array;
ConfigAttribute cfg;
List<Map<String, String>> permissions = new LinkedList<>();
for(Map<String, String> permission : permissions) {
array = new ArrayList<>();
cfg = new SecurityConfig("ADMIN");
//此处只添加了用户的名字其实还可以添加更多权限的信息例如请求方法到ConfigAttribute的集合中去此处添加的信息将会作为MyAccessDecisionManager类的decide的第三个参数
array.add(cfg);
//用权限的getUrl() 作为map的key用ConfigAttribute的集合作为 value
map.put("/admin/test", array);
}
}
@Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
if(map ==null) loadResourceDefine();
//object 中包含用户请求的request 信息
HttpServletRequest request = ((FilterInvocation) o).getHttpRequest();
AntPathRequestMatcher matcher;
String resUrl;
for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
resUrl = iter.next();
matcher = new AntPathRequestMatcher(resUrl);
if(matcher.matches(request)) {
return map.get(resUrl);
}
}
return null;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return false;
}
}

View File

@ -58,11 +58,12 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
// 创建已认证的用户密码认证对象 // 创建已认证的用户密码认证对象
public UsernamePasswordAuthenticationToken(String name, String avatar_url, int github_id, Collection<? extends GrantedAuthority> authorities) { public UsernamePasswordAuthenticationToken(String name, String avatar_url, int github_id,String Authority, Collection<? extends GrantedAuthority> authorities) {
super(authorities); super(authorities);
this.name = name; this.name = name;
this.avatar_url = avatar_url; this.avatar_url = avatar_url;
this.github_id = github_id; this.github_id = github_id;
this.Authority = Authority;
super.setAuthenticated(true); super.setAuthenticated(true);
} }

View File

@ -1,4 +1,4 @@
package io.qyi.e5.controller; package io.qyi.e5.controller.admin;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson; import com.google.gson.Gson;
@ -10,8 +10,12 @@ import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData; import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.UUID; import java.util.UUID;
@ -22,8 +26,8 @@ import java.util.UUID;
* @author: 落叶随风 * @author: 落叶随风
* @create: 2020-03-16 01:01 * @create: 2020-03-16 01:01
**/ **/
@Controller
@RestController @RestController
@RequestMapping("/admin")
public class TestController { public class TestController {
@Autowired @Autowired
RabbitTemplate rabbitTemplate; RabbitTemplate rabbitTemplate;
@ -47,5 +51,18 @@ public class TestController {
return "ok"; return "ok";
} }
@GetMapping("/emptyRedis")
public String emptyRedis() {
redisUtil.deleteALL();
return "ok";
}
@GetMapping("/test")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String test() {
return "ok";
}
} }

View File

@ -6,6 +6,7 @@ import io.qyi.e5.bean.result.ResultEnum;
import io.qyi.e5.config.security.UsernamePasswordAuthenticationToken; import io.qyi.e5.config.security.UsernamePasswordAuthenticationToken;
import io.qyi.e5.outlook.entity.Outlook; import io.qyi.e5.outlook.entity.Outlook;
import io.qyi.e5.outlook.service.IOutlookService; import io.qyi.e5.outlook.service.IOutlookService;
import io.qyi.e5.service.task.ITask;
import io.qyi.e5.util.EncryptUtil; import io.qyi.e5.util.EncryptUtil;
import io.qyi.e5.util.ResultUtil; import io.qyi.e5.util.ResultUtil;
import io.qyi.e5.util.redis.RedisUtil; import io.qyi.e5.util.redis.RedisUtil;
@ -42,6 +43,9 @@ public class AuthController {
@Value("${outlook.authorize.url}") @Value("${outlook.authorize.url}")
String authorizeUrl; String authorizeUrl;
@Autowired
ITask Task;
@RequestMapping("/receive") @RequestMapping("/receive")
public Result Receive(String code, String state, String session_state) throws Exception { public Result Receive(String code, String state, String session_state) throws Exception {
if (!redisUtil.hasKey(states + state)) { if (!redisUtil.hasKey(states + state)) {
@ -62,6 +66,8 @@ public class AuthController {
if (!authorization_code) { if (!authorization_code) {
return ResultUtil.error(-3, "clientId 或 clientSecret 填写错误!授权失败!"); return ResultUtil.error(-3, "clientId 或 clientSecret 填写错误!授权失败!");
} }
/*添加此用户进消息队列*/
Task.sendTaskOutlookMQ(outlook.getGithubId());
return ResultUtil.success(); return ResultUtil.success();
} }

View File

@ -206,6 +206,9 @@ public class OutlookServiceImpl extends ServiceImpl<OutlookMapper, Outlook> impl
count = jsonObject.get("value").getAsJsonArray().size(); count = jsonObject.get("value").getAsJsonArray().size();
} }
JsonArray value = jsonObject.get("value").getAsJsonArray(); JsonArray value = jsonObject.get("value").getAsJsonArray();
if (count == 0) {
count = value.size();
}
for (int i = 0; i < count - 1; i++) { for (int i = 0; i < count - 1; i++) {
JsonObject mail = value.get(i).getAsJsonObject(); JsonObject mail = value.get(i).getAsJsonObject();
String id = mail.get("id").getAsString(); String id = mail.get("id").getAsString();

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.qyi.e5.outlook.entity.Outlook; import io.qyi.e5.outlook.entity.Outlook;
import io.qyi.e5.outlook.service.IOutlookService; import io.qyi.e5.outlook.service.IOutlookService;
import io.qyi.e5.service.task.ITask; import io.qyi.e5.service.task.ITask;
import io.qyi.e5.util.redis.RedisUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.core.MessageProperties;
@ -33,6 +34,9 @@ public class TaskImpl implements ITask {
@Autowired @Autowired
RabbitTemplate rabbitTemplate; RabbitTemplate rabbitTemplate;
@Autowired
RedisUtil redisUtil;
@Override @Override
@Async @Async
public void sendTaskOutlookMQ(int github_id) { public void sendTaskOutlookMQ(int github_id) {
@ -42,9 +46,12 @@ public class TaskImpl implements ITask {
return; return;
} }
/*根据用户设置生成随机数*/ /*根据用户设置生成随机数*/
String Expiration = getRandom(Outlook.getCronTimeRandomStart(), Outlook.getCronTimeRandomEnd()); int Expiration = getRandom(Outlook.getCronTimeRandomStart(), Outlook.getCronTimeRandomEnd());
send(github_id, Expiration); /*将此用户信息加入redis如果存在则代表在队列中同时提前10秒过期*/
if (!redisUtil.hasKey("user.mq:" + github_id)) {
redisUtil.set("user.mq:" + github_id, 0, Expiration - 10);
send(github_id, Expiration* 1000);
}
} }
@Override @Override
@ -55,14 +62,16 @@ public class TaskImpl implements ITask {
while (iterator.hasNext()) { while (iterator.hasNext()) {
Outlook next = iterator.next(); Outlook next = iterator.next();
/*根据用户设置生成随机数*/ /*根据用户设置生成随机数*/
String Expiration = getRandom(next.getCronTimeRandomStart(), next.getCronTimeRandomEnd()); int Expiration = getRandom(next.getCronTimeRandomStart(), next.getCronTimeRandomEnd());
// System.out.println("生成随机调用时间,github ID" + next.getGithubId() + ",时间:" + Expiration); /*将此用户信息加入redis如果存在则代表在队列中同时提前10秒过期*/
send(next.getGithubId(), Expiration); if (!redisUtil.hasKey("user.mq:" + next.getGithubId())) {
redisUtil.set("user.mq:" + next.getGithubId(), 0, Expiration - 10);
send(next.getGithubId(), Expiration * 1000);
}
} }
} }
@Override @Override
@Async
public void executeE5(int github_id) { public void executeE5(int github_id) {
Outlook Outlook = outlookService.getOne(new QueryWrapper<Outlook>().eq("github_id", github_id)); Outlook Outlook = outlookService.getOne(new QueryWrapper<Outlook>().eq("github_id", github_id));
if (Outlook == null) { if (Outlook == null) {
@ -82,7 +91,7 @@ public class TaskImpl implements ITask {
* @Author: 落叶随风 * @Author: 落叶随风
* @Date: 2020/4/16 * @Date: 2020/4/16
*/ */
public void send(Object msg, String Expiration) { public void send(Object msg, int Expiration) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString()); CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("delay", "delay", msg, message -> { rabbitTemplate.convertAndSend("delay", "delay", msg, message -> {
@ -90,7 +99,7 @@ public class TaskImpl implements ITask {
// 设置这条消息的过期时间 // 设置这条消息的过期时间
// messageProperties.setExpiration(Expiration); // messageProperties.setExpiration(Expiration);
messageProperties.setHeader("x-delay",Expiration); messageProperties.setHeader("x-delay", Expiration);
return message; return message;
}, correlationData); }, correlationData);
} }
@ -105,9 +114,9 @@ public class TaskImpl implements ITask {
* @Author: 落叶随风 * @Author: 落叶随风
* @Date: 2020/4/16 * @Date: 2020/4/16
*/ */
public String getRandom(int start, int end) { public int getRandom(int start, int end) {
Random r = new Random(); Random r = new Random();
String Expiration = String.valueOf((r.nextInt(end - start + 1) + start) * 1000); int Expiration = (r.nextInt(end - start + 1) + start);
return Expiration; return Expiration;
} }
} }

View File

@ -49,6 +49,19 @@ public class RedisUtil {
} }
} }
/**
* 删除所有键值对
* @title deleteALl
* @description
* @author 落叶随风
* @updateTime 2020/4/22 22:53
* @throws
*/
public void deleteALL() {
Set<String> keys = redisTemplate.keys("*");
redisTemplate.delete(keys);
}
/** /**
* 根据key 获取过期时间 * 根据key 获取过期时间
* *

View File

@ -4,7 +4,7 @@
<!--Configuration后面的status这个用于设置log4j2自身内部的信息输出可以不设置 <!--Configuration后面的status这个用于设置log4j2自身内部的信息输出可以不设置
当设置成trace时会看到log4j2内部各种详细输出--> 当设置成trace时会看到log4j2内部各种详细输出-->
<!--monitorIntervalLog4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数--> <!--monitorIntervalLog4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="DEBUG" monitorInterval="5"> <configuration status="INFO" monitorInterval="5">
<Properties> <Properties>
<!-- 日志模板 --> <!-- 日志模板 -->
<Property name="log_pattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> <Property name="log_pattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>