diff --git a/pom.xml b/pom.xml index 46ef961..31261bd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.2.4.RELEASE + 2.3.1.RELEASE io.qyi @@ -35,16 +35,23 @@ - + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot spring-boot-starter-log4j2 - - - org.springframework.boot - spring-boot-starter-freemarker - org.springframework.boot diff --git a/src/main/java/io/qyi/e5/config/security/MyAccessDecisionManager.java b/src/main/java/io/qyi/e5/config/security/MyAccessDecisionManager.java new file mode 100644 index 0000000..2df3486 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/security/MyAccessDecisionManager.java @@ -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 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 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 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; + } +} diff --git a/src/main/java/io/qyi/e5/config/security/MyInvocationSecurityMetadataSourceService.java b/src/main/java/io/qyi/e5/config/security/MyInvocationSecurityMetadataSourceService.java new file mode 100644 index 0000000..fc16cc7 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/security/MyInvocationSecurityMetadataSourceService.java @@ -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> map =null; + /** + * 加载权限表中所有权限 + */ + public void loadResourceDefine(){ + map = new HashMap<>(); + Collection array; + ConfigAttribute cfg; + List> permissions = new LinkedList<>(); + for(Map 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 getAttributes(Object o) throws IllegalArgumentException { + if(map ==null) loadResourceDefine(); + //object 中包含用户请求的request 信息 + HttpServletRequest request = ((FilterInvocation) o).getHttpRequest(); + AntPathRequestMatcher matcher; + String resUrl; + for(Iterator 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 getAllConfigAttributes() { + return null; + } + + @Override + public boolean supports(Class aClass) { + return false; + } +} diff --git a/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationToken.java b/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationToken.java index 43f626f..a465c9e 100644 --- a/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationToken.java +++ b/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationToken.java @@ -58,11 +58,12 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT // 创建已认证的用户密码认证对象 - public UsernamePasswordAuthenticationToken(String name, String avatar_url, int github_id, Collection authorities) { + public UsernamePasswordAuthenticationToken(String name, String avatar_url, int github_id,String Authority, Collection authorities) { super(authorities); this.name = name; this.avatar_url = avatar_url; this.github_id = github_id; + this.Authority = Authority; super.setAuthenticated(true); } diff --git a/src/main/java/io/qyi/e5/controller/TestController.java b/src/main/java/io/qyi/e5/controller/admin/TestController.java similarity index 67% rename from src/main/java/io/qyi/e5/controller/TestController.java rename to src/main/java/io/qyi/e5/controller/admin/TestController.java index 3475272..2f61b80 100644 --- a/src/main/java/io/qyi/e5/controller/TestController.java +++ b/src/main/java/io/qyi/e5/controller/admin/TestController.java @@ -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.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.core.RabbitTemplate; 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.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.UUID; @@ -22,8 +26,8 @@ import java.util.UUID; * @author: 落叶随风 * @create: 2020-03-16 01:01 **/ -@Controller @RestController +@RequestMapping("/admin") public class TestController { @Autowired RabbitTemplate rabbitTemplate; @@ -47,5 +51,18 @@ public class TestController { return "ok"; } + @GetMapping("/emptyRedis") + public String emptyRedis() { + redisUtil.deleteALL(); + return "ok"; + } + + @GetMapping("/test") + @PreAuthorize("hasRole('ROLE_ADMIN')") + public String test() { + return "ok"; + } + + } diff --git a/src/main/java/io/qyi/e5/outlook/controller/AuthController.java b/src/main/java/io/qyi/e5/outlook/controller/AuthController.java index 61ef64d..23ea46e 100644 --- a/src/main/java/io/qyi/e5/outlook/controller/AuthController.java +++ b/src/main/java/io/qyi/e5/outlook/controller/AuthController.java @@ -6,6 +6,7 @@ import io.qyi.e5.bean.result.ResultEnum; import io.qyi.e5.config.security.UsernamePasswordAuthenticationToken; import io.qyi.e5.outlook.entity.Outlook; 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.ResultUtil; import io.qyi.e5.util.redis.RedisUtil; @@ -42,6 +43,9 @@ public class AuthController { @Value("${outlook.authorize.url}") String authorizeUrl; + @Autowired + ITask Task; + @RequestMapping("/receive") public Result Receive(String code, String state, String session_state) throws Exception { if (!redisUtil.hasKey(states + state)) { @@ -62,6 +66,8 @@ public class AuthController { if (!authorization_code) { return ResultUtil.error(-3, "clientId 或 clientSecret 填写错误!授权失败!"); } + /*添加此用户进消息队列*/ + Task.sendTaskOutlookMQ(outlook.getGithubId()); return ResultUtil.success(); } diff --git a/src/main/java/io/qyi/e5/outlook/service/impl/OutlookServiceImpl.java b/src/main/java/io/qyi/e5/outlook/service/impl/OutlookServiceImpl.java index c17658a..a698dc4 100644 --- a/src/main/java/io/qyi/e5/outlook/service/impl/OutlookServiceImpl.java +++ b/src/main/java/io/qyi/e5/outlook/service/impl/OutlookServiceImpl.java @@ -206,6 +206,9 @@ public class OutlookServiceImpl extends ServiceImpl impl count = jsonObject.get("value").getAsJsonArray().size(); } JsonArray value = jsonObject.get("value").getAsJsonArray(); + if (count == 0) { + count = value.size(); + } for (int i = 0; i < count - 1; i++) { JsonObject mail = value.get(i).getAsJsonObject(); String id = mail.get("id").getAsString(); diff --git a/src/main/java/io/qyi/e5/service/task/impl/TaskImpl.java b/src/main/java/io/qyi/e5/service/task/impl/TaskImpl.java index 29d0a44..88b7bb4 100644 --- a/src/main/java/io/qyi/e5/service/task/impl/TaskImpl.java +++ b/src/main/java/io/qyi/e5/service/task/impl/TaskImpl.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import io.qyi.e5.outlook.entity.Outlook; import io.qyi.e5.outlook.service.IOutlookService; import io.qyi.e5.service.task.ITask; +import io.qyi.e5.util.redis.RedisUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.MessageProperties; @@ -33,6 +34,9 @@ public class TaskImpl implements ITask { @Autowired RabbitTemplate rabbitTemplate; + @Autowired + RedisUtil redisUtil; + @Override @Async public void sendTaskOutlookMQ(int github_id) { @@ -42,9 +46,12 @@ public class TaskImpl implements ITask { return; } /*根据用户设置生成随机数*/ - String Expiration = getRandom(Outlook.getCronTimeRandomStart(), Outlook.getCronTimeRandomEnd()); - send(github_id, Expiration); - + int Expiration = getRandom(Outlook.getCronTimeRandomStart(), Outlook.getCronTimeRandomEnd()); + /*将此用户信息加入redis,如果存在则代表在队列中,同时提前10秒过期*/ + if (!redisUtil.hasKey("user.mq:" + github_id)) { + redisUtil.set("user.mq:" + github_id, 0, Expiration - 10); + send(github_id, Expiration* 1000); + } } @Override @@ -55,14 +62,16 @@ public class TaskImpl implements ITask { while (iterator.hasNext()) { Outlook next = iterator.next(); /*根据用户设置生成随机数*/ - String Expiration = getRandom(next.getCronTimeRandomStart(), next.getCronTimeRandomEnd()); -// System.out.println("生成随机调用时间,github ID" + next.getGithubId() + ",时间:" + Expiration); - send(next.getGithubId(), Expiration); + int Expiration = getRandom(next.getCronTimeRandomStart(), next.getCronTimeRandomEnd()); + /*将此用户信息加入redis,如果存在则代表在队列中,同时提前10秒过期*/ + if (!redisUtil.hasKey("user.mq:" + next.getGithubId())) { + redisUtil.set("user.mq:" + next.getGithubId(), 0, Expiration - 10); + send(next.getGithubId(), Expiration * 1000); + } } } @Override - @Async public void executeE5(int github_id) { Outlook Outlook = outlookService.getOne(new QueryWrapper().eq("github_id", github_id)); if (Outlook == null) { @@ -82,7 +91,7 @@ public class TaskImpl implements ITask { * @Author: 落叶随风 * @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()); rabbitTemplate.convertAndSend("delay", "delay", msg, message -> { @@ -90,7 +99,7 @@ public class TaskImpl implements ITask { // 设置这条消息的过期时间 // messageProperties.setExpiration(Expiration); - messageProperties.setHeader("x-delay",Expiration); + messageProperties.setHeader("x-delay", Expiration); return message; }, correlationData); } @@ -105,9 +114,9 @@ public class TaskImpl implements ITask { * @Author: 落叶随风 * @Date: 2020/4/16 */ - public String getRandom(int start, int end) { + public int getRandom(int start, int end) { 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; } } diff --git a/src/main/java/io/qyi/e5/util/redis/RedisUtil.java b/src/main/java/io/qyi/e5/util/redis/RedisUtil.java index 9a6bddb..ec89cf2 100644 --- a/src/main/java/io/qyi/e5/util/redis/RedisUtil.java +++ b/src/main/java/io/qyi/e5/util/redis/RedisUtil.java @@ -49,6 +49,19 @@ public class RedisUtil { } } + /** + * 删除所有键值对 + * @title deleteALl + * @description + * @author 落叶随风 + * @updateTime 2020/4/22 22:53 + * @throws + */ + public void deleteALL() { + Set keys = redisTemplate.keys("*"); + redisTemplate.delete(keys); + } + /** * 根据key 获取过期时间 * diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 13784fc..5999d31 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -4,7 +4,7 @@ - +