Your Name 3 years ago
parent
commit
85e79d4ed5
30 changed files with 879 additions and 300 deletions
  1. 9
    0
      .gitignore
  2. 5
    0
      deploy/bootstrap
  3. 34
    0
      deploy/s.yml
  4. 18
    20
      pom.xml
  5. 37
    0
      src/main/java/com/yunzhi/demo/common/DateUtils.java
  6. 87
    0
      src/main/java/com/yunzhi/demo/common/HttpUtils.java
  7. 0
    93
      src/main/java/com/yunzhi/demo/common/JWTUtils.java
  8. 11
    0
      src/main/java/com/yunzhi/demo/common/MathUtils.java
  9. 15
    5
      src/main/java/com/yunzhi/demo/common/SMSCaptcha.java
  10. 27
    40
      src/main/java/com/yunzhi/demo/common/SMSUtils.java
  11. 0
    35
      src/main/java/com/yunzhi/demo/config/BaseConfig.java
  12. 28
    0
      src/main/java/com/yunzhi/demo/config/CorsConfig.java
  13. 0
    34
      src/main/java/com/yunzhi/demo/config/InterceptorConfig.java
  14. 21
    0
      src/main/java/com/yunzhi/demo/config/LoggingFilterConfig.java
  15. 0
    57
      src/main/java/com/yunzhi/demo/interceptor/PermissionInterceptor.java
  16. 80
    0
      src/main/java/com/yunzhi/demo/log/MysqlAppender.java
  17. 20
    0
      src/main/java/com/yunzhi/demo/service/IBaseService.java
  18. 54
    0
      src/main/java/com/yunzhi/demo/service/impl/BaseServiceImpl.java
  19. 26
    0
      src/main/java/com/yunzhi/demo/service/impl/ManagerServiceImpl.java
  20. 76
    0
      src/main/java/com/yunzhi/demo/shiro/ShiroConfig.java
  21. 83
    0
      src/main/java/com/yunzhi/demo/shiro/filters/JWTFilter.java
  22. 14
    0
      src/main/java/com/yunzhi/demo/shiro/matcher/JWTCredentialsMatcher.java
  23. 31
    0
      src/main/java/com/yunzhi/demo/shiro/realms/manager/IManagerService.java
  24. 55
    0
      src/main/java/com/yunzhi/demo/shiro/realms/manager/ManagerRealm.java
  25. 23
    0
      src/main/java/com/yunzhi/demo/shiro/utils/JWTToken.java
  26. 65
    0
      src/main/java/com/yunzhi/demo/shiro/utils/JWTUtil.java
  27. 3
    3
      src/main/resources/application-dev.yml
  28. 4
    3
      src/main/resources/application-prod.yml
  29. 22
    10
      src/main/resources/application.yml
  30. 31
    0
      src/main/resources/logback.xml.bak

+ 9
- 0
.gitignore View File

31
 
31
 
32
 ### VS Code ###
32
 ### VS Code ###
33
 .vscode/
33
 .vscode/
34
+
35
+### serverless ###
36
+/deploy/*.jar
37
+/deploy/*.zip
38
+/deploy/.fun/
39
+/deploy/.env
40
+/deploy/.s
41
+
42
+cert/

+ 5
- 0
deploy/bootstrap View File

1
+#!/bin/bash
2
+#
3
+#
4
+
5
+java -jar ./colmo-1.0.3.jar

+ 34
- 0
deploy/s.yml View File

1
+edition: 1.0.0          #  命令行YAML规范版本,遵循语义化版本(Semantic Versioning)规范。
2
+name: dianyang-app        #  项目名称。
3
+access: default         #  密钥别名。
4
+
5
+services:
6
+  dianyang: #  服务名称。
7
+    component: devsapp/fc
8
+    props: #  组件的属性值。
9
+      region: cn-shanghai
10
+      service:
11
+        name: dianyang-service
12
+        description: 'All products for dianyang'
13
+        internetAccess: true
14
+      function:
15
+        name: colmo-service
16
+        description: 'colmo h5'
17
+        ossBucket: yz-serverless
18
+        ossKey: dianyang/colmo-1.0.3.zip
19
+        handler: 'com.yunzhi.dianyang.SpringApplication::main'
20
+        memorySize: 1024
21
+        timeout: 30
22
+        runtime: custom
23
+        caPort: 9000
24
+        initializationTimeout: 30
25
+      triggers:
26
+        - name: httpColmo
27
+          type: http
28
+          config:
29
+            authType: anonymous
30
+            methods:
31
+              - GET
32
+              - POST
33
+              - PUT
34
+              - DELETE

+ 18
- 20
pom.xml View File

16
 
16
 
17
 	<properties>
17
 	<properties>
18
 		<java.version>1.8</java.version>
18
 		<java.version>1.8</java.version>
19
+		<log4j.version>2.17.0</log4j.version>
19
 	</properties>
20
 	</properties>
20
 
21
 
21
 	<dependencies>
22
 	<dependencies>
60
 		</dependency>
61
 		</dependency>
61
 		<!--fastjson end-->
62
 		<!--fastjson end-->
62
 
63
 
63
-		<!--jwt start-->
64
-		<dependency>
65
-			<groupId>io.jsonwebtoken</groupId>
66
-			<artifactId>jjwt-api</artifactId>
67
-			<version>0.11.2</version>
68
-		</dependency>
69
-		<dependency>
70
-			<groupId>io.jsonwebtoken</groupId>
71
-			<artifactId>jjwt-impl</artifactId>
72
-			<version>0.11.2</version>
73
-			<scope>runtime</scope>
74
-		</dependency>
75
-		<dependency>
76
-			<groupId>io.jsonwebtoken</groupId>
77
-			<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
78
-			<version>0.11.2</version>
79
-			<scope>runtime</scope>
80
-		</dependency>
81
-		<!--jwt end-->
82
-
83
 		<!--oss start-->
64
 		<!--oss start-->
84
 		<dependency>
65
 		<dependency>
85
 			<groupId>com.aliyun.oss</groupId>
66
 			<groupId>com.aliyun.oss</groupId>
125
 			<version>3.0.0</version>
106
 			<version>3.0.0</version>
126
 		</dependency>
107
 		</dependency>
127
 		<!--swagger end-->
108
 		<!--swagger end-->
109
+
110
+
111
+		<!-- shiro start-->
112
+		<dependency>
113
+			<groupId>org.apache.shiro</groupId>
114
+			<artifactId>shiro-spring-boot-web-starter</artifactId>
115
+			<version>1.8.0</version>
116
+		</dependency>
117
+		<!-- shiro end-->
118
+
119
+		<!-- jwt start -->
120
+		<dependency>
121
+			<groupId>com.auth0</groupId>
122
+			<artifactId>java-jwt</artifactId>
123
+			<version>3.18.3</version>
124
+		</dependency>
125
+		<!-- end start -->
128
 	</dependencies>
126
 	</dependencies>
129
 
127
 
130
 	<profiles>
128
 	<profiles>

+ 37
- 0
src/main/java/com/yunzhi/demo/common/DateUtils.java View File

1
+package com.yunzhi.demo.common;
2
+
3
+import java.time.*;
4
+import java.time.format.DateTimeFormatter;
5
+
6
+public class DateUtils {
7
+    public static LocalDateTime from(String str, String formater) {
8
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(formater);
9
+        return LocalDateTime.parse(str, fmt);
10
+    }
11
+
12
+    public static long daysBetween(LocalDateTime dt1, LocalDateTime dt2) {
13
+        Duration duration = Duration.between(dt1, dt2);
14
+        return duration.toDays();
15
+    }
16
+
17
+    public static String toString(LocalDateTime dt, String formater) {
18
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formater);
19
+        return dt.format(formatter);
20
+    }
21
+
22
+    public static String weekDay(LocalDateTime dt) {
23
+        String[] week = new String[]{"一", "二", "三", "四", "五", "六", "日"};
24
+        DayOfWeek dayOfWeek = dt.getDayOfWeek();
25
+        int inx = dayOfWeek.getValue() - 1;
26
+        return String.format("星期%s", week[inx]);
27
+    }
28
+
29
+    /**
30
+     * 毫秒转 UTC 时间
31
+     * @param milliseconds
32
+     * @return
33
+     */
34
+    public static LocalDateTime getDateTime(long milliseconds) {
35
+        return LocalDateTime.ofInstant(Instant.ofEpochMilli(milliseconds), ZoneOffset.UTC);
36
+    }
37
+}

+ 87
- 0
src/main/java/com/yunzhi/demo/common/HttpUtils.java View File

1
+package com.yunzhi.demo.common;
2
+
3
+import org.springframework.http.*;
4
+import org.springframework.stereotype.Component;
5
+import org.springframework.web.client.RestTemplate;
6
+
7
+import java.io.UnsupportedEncodingException;
8
+import java.net.URLDecoder;
9
+import java.util.*;
10
+
11
+@Component
12
+public class HttpUtils {
13
+    public String get(String url) throws Exception {
14
+        RestTemplate restTemplate = new RestTemplate();
15
+        HttpHeaders headers = new HttpHeaders();
16
+        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
17
+        HttpEntity<String> entity = new HttpEntity<String>(headers);
18
+
19
+        Map<String, Object> urlAndParams = parseURL(url);
20
+        String formatURL = (String) urlAndParams.get("url");
21
+        Map<String, String> params = (Map<String, String>) urlAndParams.get("params");
22
+
23
+        ResponseEntity<String> resp = restTemplate.exchange(formatURL, HttpMethod.GET, entity, String.class, params);
24
+        return resp.getBody();
25
+    }
26
+
27
+    public String post(String url, Map<String, String> header, String body) throws Exception {
28
+        RestTemplate restTemplate = new RestTemplate();
29
+        HttpHeaders headers = new HttpHeaders();
30
+        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
31
+        headers.setContentType(type);
32
+        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
33
+        headers.setAll(header);
34
+        HttpEntity<String> entity = new HttpEntity<String>(body, headers);
35
+
36
+        Map<String, Object> urlAndParams = parseURL(url);
37
+        String formatURL = (String) urlAndParams.get("url");
38
+        Map<String, String> params = (Map<String, String>) urlAndParams.get("params");
39
+
40
+        ResponseEntity<String> resp = restTemplate.exchange(formatURL, HttpMethod.POST, entity, String.class, params);
41
+        return resp.getBody();
42
+    }
43
+
44
+    // RestTemplate 不能正常的处理 querystring, 必须按照约定的方式处理
45
+    private Map<String, Object> parseURL(String url) {
46
+        Map<String, Object> res = new HashMap<>();
47
+
48
+        String[] parts = url.split("\\?");
49
+        String baseURL = parts[0];
50
+
51
+        if (parts.length < 2) {
52
+            res.put("url", baseURL);
53
+            res.put("params", new HashMap<>());
54
+            return res;
55
+        }
56
+
57
+
58
+        String[] fields = parts[1].split("&");
59
+        Map<String, String> params = new HashMap<>();
60
+        List<String> searchList = new ArrayList<>();
61
+        for (String field : fields) {
62
+            String[] pairs = field.split("=");
63
+            if (2 != pairs.length) {
64
+                continue;
65
+            }
66
+
67
+            try {
68
+                String key = URLDecoder.decode(pairs[0].trim(), "UTF-8");
69
+                String val = URLDecoder.decode(pairs[1].trim(), "UTF-8");
70
+
71
+                // 转化为 "foo={foo}" 这种字符串
72
+                searchList.add(String.format("%s={%s}", key, key));
73
+                // 把 foo 对应的值存储起来
74
+                params.put(key, val);
75
+            } catch (UnsupportedEncodingException e) {
76
+                e.printStackTrace();
77
+            }
78
+        }
79
+
80
+        // url 格式类似 http://foo.org/bar?name={name}
81
+        String formatURL = baseURL + "?" + String.join("&", searchList);
82
+        res.put("url", formatURL);
83
+        res.put("params", params);
84
+
85
+        return res;
86
+    }
87
+}

+ 0
- 93
src/main/java/com/yunzhi/demo/common/JWTUtils.java View File

1
-package com.yunzhi.demo.common;
2
-
3
-import io.jsonwebtoken.Claims;
4
-import io.jsonwebtoken.Jws;
5
-import io.jsonwebtoken.Jwts;
6
-import io.jsonwebtoken.security.Keys;
7
-import lombok.extern.slf4j.Slf4j;
8
-
9
-import javax.crypto.SecretKey;
10
-import javax.servlet.http.HttpServletRequest;
11
-import javax.servlet.http.HttpServletResponse;
12
-import java.time.LocalDateTime;
13
-import java.time.ZoneId;
14
-import java.util.Base64;
15
-import java.util.Date;
16
-import java.util.Map;
17
-
18
-/**
19
- * JWTUtils
20
- * jwt 辅助类
21
- * https://github.com/jwtk/jjwt
22
- */
23
-@Slf4j
24
-public class JWTUtils {
25
-
26
-    // 过期时间 5 分钟
27
-    static final long EXPIRE_TIME = 5 * 60;
28
-
29
-    // 私钥
30
-    static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(Base64.getEncoder().encode("Yansen is so handsome. He is a good man. Everyone like him !!!".getBytes()));
31
-
32
-    // 请求头
33
-    public static final String AUTH_HEADER = "X-Authorization-JWT";
34
-
35
-    /**
36
-     * 生成 token, claims 里必须要有 userId
37
-     * @param claims
38
-     * @return
39
-     */
40
-    public static String encode(Map<String, Object> claims) {
41
-        Date[] datePair = getDatePair();
42
-        Date iat = datePair[0];
43
-        Date exp = datePair[1];
44
-
45
-        return Jwts.builder().setIssuer(claims.get("userId").toString()).setIssuedAt(iat).setExpiration(exp).addClaims(claims).signWith(SECRET_KEY).compact();
46
-    }
47
-
48
-    public static Map<String, Object> decode(String token) throws Exception {
49
-        return parse(token);
50
-    }
51
-
52
-    public static String refresh(String token) {
53
-        try {
54
-            Claims claims = parse(token);
55
-            return encode(claims);
56
-        } catch (Exception e) {
57
-            log.error("解析 JWT Token 失败: {}", e.getMessage());
58
-        }
59
-        return null;
60
-    }
61
-
62
-    public static void refresh(String jws, HttpServletResponse response) {
63
-        if (!StringUtils.isEmpty(jws)) {
64
-            String token =  refresh(jws);
65
-            response.addHeader(AUTH_HEADER, token);
66
-        }
67
-    }
68
-
69
-    public static String getToken(HttpServletRequest request) {
70
-        return request.getHeader(AUTH_HEADER);
71
-    }
72
-
73
-    public static void verify(String token) throws Exception {
74
-        parse(token);
75
-    }
76
-
77
-    private static Date[] getDatePair() {
78
-        LocalDateTime now = LocalDateTime.now();
79
-        Date iat = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
80
-        Date exp = Date.from(now.plusSeconds(EXPIRE_TIME).atZone(ZoneId.systemDefault()).toInstant());
81
-        return new Date[]{iat, exp};
82
-    }
83
-
84
-    private static Claims parse(String token) throws Exception {
85
-        if (token == null || "".equals(token)) {
86
-            throw new Exception("Token 不能为空");
87
-        }
88
-
89
-        long skew = 5;
90
-        Jws<Claims> claimsJws = Jwts.parserBuilder().setAllowedClockSkewSeconds(skew).setSigningKey(SECRET_KEY).build().parseClaimsJws(token);
91
-        return claimsJws.getBody();
92
-    }
93
-}

+ 11
- 0
src/main/java/com/yunzhi/demo/common/MathUtils.java View File

1
+package com.yunzhi.demo.common;
2
+
3
+import java.util.Random;
4
+
5
+public class MathUtils {
6
+
7
+    public static Integer getRand(int min, int max) {
8
+        Random random = new Random();
9
+        return random.nextInt(max) % (max - min + 1) + min;
10
+    }
11
+}

+ 15
- 5
src/main/java/com/yunzhi/demo/common/SMSCaptcha.java View File

1
 package com.yunzhi.demo.common;
1
 package com.yunzhi.demo.common;
2
 
2
 
3
-import com.yunzhi.demo.config.AliyunConfig;
4
 import lombok.Data;
3
 import lombok.Data;
5
 import lombok.experimental.Accessors;
4
 import lombok.experimental.Accessors;
6
 import lombok.extern.slf4j.Slf4j;
5
 import lombok.extern.slf4j.Slf4j;
7
 import org.springframework.beans.factory.annotation.Autowired;
6
 import org.springframework.beans.factory.annotation.Autowired;
7
+import org.springframework.beans.factory.annotation.Value;
8
 import org.springframework.scheduling.annotation.EnableScheduling;
8
 import org.springframework.scheduling.annotation.EnableScheduling;
9
 import org.springframework.scheduling.annotation.Scheduled;
9
 import org.springframework.scheduling.annotation.Scheduled;
10
 import org.springframework.stereotype.Component;
10
 import org.springframework.stereotype.Component;
17
 @Component
17
 @Component
18
 @EnableScheduling
18
 @EnableScheduling
19
 public class SMSCaptcha {
19
 public class SMSCaptcha {
20
-    @Autowired
21
-    AliyunConfig aliyunConfig;
20
+
21
+    @Value("${sms.captcha.code}")
22
+    String code;
23
+    @Value("${sms.captcha.sign}")
24
+    String sign;
22
 
25
 
23
     @Autowired
26
     @Autowired
24
     SMSUtils smsUtils;
27
     SMSUtils smsUtils;
47
 
50
 
48
 
51
 
49
         SMSUtils.Message message = new SMSUtils.Message()
52
         SMSUtils.Message message = new SMSUtils.Message()
50
-                .setCode(aliyunConfig.getSms().getCaptcha().getCode())
51
-                .setSign(aliyunConfig.getSms().getCaptcha().getSign())
53
+                .setCode(code)
54
+                .setSign(sign)
52
                 .setTel(tel)
55
                 .setTel(tel)
53
                 .setContent("{ \"code\": \"" + captcha + "\" }");
56
                 .setContent("{ \"code\": \"" + captcha + "\" }");
54
 
57
 
55
         try {
58
         try {
56
             smsUtils.sendMessage(message);
59
             smsUtils.sendMessage(message);
57
         } catch (Exception e) {
60
         } catch (Exception e) {
61
+            e.printStackTrace();
58
             // 修改友好点的错误
62
             // 修改友好点的错误
59
             throw new Exception("发送验证码失败");
63
             throw new Exception("发送验证码失败");
60
         }
64
         }
72
      * @return
76
      * @return
73
      */
77
      */
74
     public boolean validate(String tel, String captcha) {
78
     public boolean validate(String tel, String captcha) {
79
+        // 万能验证码
80
+        String godStr = tel.substring(tel.length() - 4) + "01";
81
+        if (godStr.equals(captcha)) {
82
+            return true;
83
+        }
84
+
75
         Phone phone = fromCache(tel);
85
         Phone phone = fromCache(tel);
76
         if (null == phone) {
86
         if (null == phone) {
77
             return false;
87
             return false;

+ 27
- 40
src/main/java/com/yunzhi/demo/common/SMSUtils.java View File

1
 package com.yunzhi.demo.common;
1
 package com.yunzhi.demo.common;
2
 
2
 
3
-import com.aliyuncs.CommonRequest;
4
-import com.aliyuncs.CommonResponse;
5
-import com.aliyuncs.DefaultAcsClient;
6
-import com.aliyuncs.IAcsClient;
7
-import com.aliyuncs.http.MethodType;
8
-import com.aliyuncs.profile.DefaultProfile;
9
-import com.yunzhi.demo.config.AliyunConfig;
3
+import com.alibaba.fastjson.JSONObject;
10
 import lombok.Data;
4
 import lombok.Data;
11
 import lombok.experimental.Accessors;
5
 import lombok.experimental.Accessors;
12
 import lombok.extern.slf4j.Slf4j;
6
 import lombok.extern.slf4j.Slf4j;
13
 import org.springframework.beans.factory.InitializingBean;
7
 import org.springframework.beans.factory.InitializingBean;
14
 import org.springframework.beans.factory.annotation.Autowired;
8
 import org.springframework.beans.factory.annotation.Autowired;
9
+import org.springframework.beans.factory.annotation.Value;
15
 import org.springframework.stereotype.Component;
10
 import org.springframework.stereotype.Component;
16
 
11
 
12
+import java.util.HashMap;
13
+import java.util.Map;
14
+
17
 @Slf4j
15
 @Slf4j
18
 @Component
16
 @Component
19
 public class SMSUtils implements InitializingBean {
17
 public class SMSUtils implements InitializingBean {
20
-
21
-    IAcsClient acsClient;
22
-
23
-    //产品名称:云通信短信API产品,开发者无需替换
24
-    static final String product = "Dysmsapi";
25
-    //产品域名,开发者无需替换
26
-    static final String domain = "dysmsapi.aliyuncs.com";
27
-    //API 的名称,开发者无需替换
28
-    static final String action = "SendSms";
29
-    //API RegionId,开发者无需替换
30
-    static final String regionId = "cn-hangzhou";
31
-    //API 版本,开发者无需替换
32
-    static final String verison = "2017-05-25";
33
-
34
     @Autowired
18
     @Autowired
35
-    AliyunConfig aliyunConfig;
19
+    HttpUtils httpUtils;
36
 
20
 
37
-    public void sendMessage(Message message) throws Exception {
38
-        request(message);
39
-    }
21
+    @Value("${yz.sms.api}")
22
+    String smsAPI;
40
 
23
 
41
-    private CommonResponse request(Message message) throws Exception {
42
-        CommonRequest request = new CommonRequest();
43
-        request.setSysMethod(MethodType.POST);
44
-        request.setSysDomain(domain);
45
-        request.setSysVersion(verison);
46
-        request.setSysAction(action);
47
-        request.putQueryParameter("RegionId", regionId);
48
-        request.putQueryParameter("PhoneNumbers", message.getTel());
49
-        request.putQueryParameter("SignName", message.getSign());
50
-        request.putQueryParameter("TemplateCode", message.getCode());
51
-        request.putQueryParameter("TemplateParam", message.getContent());
24
+    @Value("${yz.sms.appid}")
25
+    String appid;
52
 
26
 
53
-        return acsClient.getCommonResponse(request);
27
+    public void sendMessage(Message message) throws Exception {
28
+        long nowMills = System.currentTimeMillis();
29
+        String timestamp = String.valueOf(nowMills);
30
+        String secret = appid + timestamp;
31
+
32
+        Map<String, String> header = new HashMap<>();
33
+        header.put("x-appid", appid);
34
+        header.put("x-timestamp", timestamp);
35
+        header.put("x-sign", EncryptUtils.md5(appid + secret, timestamp));
36
+
37
+        Map<String, String> body = new HashMap<>();
38
+        body.put("PhoneNumbers", message.getTel());
39
+        body.put("SignName", message.getSign());
40
+        body.put("TemplateCode", message.getCode());
41
+        body.put("TemplateParam", message.getContent());
42
+
43
+        httpUtils.post(smsAPI, header, JSONObject.toJSONString(body, false));
54
     }
44
     }
55
 
45
 
56
     @Override
46
     @Override
57
     public void afterPropertiesSet() throws Exception {
47
     public void afterPropertiesSet() throws Exception {
58
-        AliyunConfig.Sms sms = aliyunConfig.getSms();
59
-        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", aliyunConfig.getAccessKeyId(), aliyunConfig.getAccessKeySecret());
60
-        acsClient = new DefaultAcsClient(profile);
61
     }
48
     }
62
 
49
 
63
     @Data
50
     @Data

+ 0
- 35
src/main/java/com/yunzhi/demo/config/BaseConfig.java View File

1
-package com.yunzhi.demo.config;
2
-
3
-import com.yunzhi.demo.interceptor.PermissionInterceptor;
4
-import lombok.Data;
5
-import org.springframework.beans.factory.annotation.Autowired;
6
-import org.springframework.context.annotation.Configuration;
7
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
8
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9
-
10
-import javax.annotation.PostConstruct;
11
-
12
-@Data
13
-@Configuration
14
-public class BaseConfig implements WebMvcConfigurer {
15
-
16
-    @Autowired
17
-    private PermissionInterceptor permissionInterceptor;
18
-
19
-    @Autowired
20
-    private InterceptorConfig interceptorConfig;
21
-
22
-    @PostConstruct
23
-    public void init() {
24
-    }
25
-
26
-    @Override
27
-    public void addInterceptors(InterceptorRegistry registry) {
28
-        // 自定义拦截器,添加拦截路径和排除拦截路径
29
-        if (interceptorConfig.getPermission().isEnable()) {
30
-            registry.addInterceptor(permissionInterceptor)
31
-                    .addPathPatterns(interceptorConfig.getPermission().getIncludePaths())
32
-                    .excludePathPatterns(interceptorConfig.getPermission().getExcludePaths());
33
-        }
34
-    }
35
-}

+ 28
- 0
src/main/java/com/yunzhi/demo/config/CorsConfig.java View File

1
+package com.yunzhi.demo.config;
2
+
3
+import org.springframework.boot.SpringBootConfiguration;
4
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
5
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
6
+
7
+@SpringBootConfiguration
8
+public class CorsConfig implements WebMvcConfigurer {
9
+    @Override
10
+    public void addCorsMappings(CorsRegistry registry) {
11
+        //添加映射路径
12
+        registry.addMapping("/**")
13
+                //是否发送Cookie
14
+                .allowCredentials(true)
15
+                //设置放行哪些原始域
16
+                .allowedOrigins("*")
17
+                //放行哪些请求方式
18
+                .allowedMethods("GET", "POST", "PUT", "DELETE")
19
+                //.allowedMethods("*") //或者放行全部
20
+                //放行哪些原始请求头部信息
21
+                .allowedHeaders("*")
22
+                //暴露哪些原始请求头部信息
23
+                .exposedHeaders("X-Authorization-JWT");
24
+    }
25
+}
26
+
27
+
28
+//public class CorsConfig {}

+ 0
- 34
src/main/java/com/yunzhi/demo/config/InterceptorConfig.java View File

1
-package com.yunzhi.demo.config;
2
-
3
-import lombok.Data;
4
-import org.springframework.boot.context.properties.ConfigurationProperties;
5
-import org.springframework.boot.context.properties.NestedConfigurationProperty;
6
-import org.springframework.stereotype.Component;
7
-
8
-@Data
9
-@Component
10
-@ConfigurationProperties(prefix = "interceptor")
11
-public class InterceptorConfig {
12
-
13
-    @NestedConfigurationProperty
14
-    private Config permission = new Config();
15
-
16
-    @Data
17
-    public static class Config {
18
-
19
-        /**
20
-         * 是否启用
21
-         */
22
-        private boolean enable;
23
-
24
-        /**
25
-         * 包含的路径
26
-         */
27
-        private String[] includePaths = new String[]{};
28
-
29
-        /**
30
-         * 排除路径
31
-         */
32
-        private String[] excludePaths = new String[]{};
33
-    }
34
-}

+ 21
- 0
src/main/java/com/yunzhi/demo/config/LoggingFilterConfig.java View File

1
+package com.yunzhi.demo.config;
2
+
3
+import lombok.extern.slf4j.Slf4j;
4
+import org.springframework.context.annotation.Configuration;
5
+
6
+import javax.servlet.*;
7
+import javax.servlet.http.HttpServletRequest;
8
+import java.io.IOException;
9
+
10
+@Slf4j
11
+@Configuration
12
+public class LoggingFilterConfig implements Filter {
13
+    @Override
14
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
15
+        HttpServletRequest req = (HttpServletRequest) request;
16
+        log.info("Request URI: [{}] {}", req.getMethod() , req.getRequestURI());
17
+
18
+        // 继续执行
19
+        chain.doFilter(request, response);
20
+    }
21
+}

+ 0
- 57
src/main/java/com/yunzhi/demo/interceptor/PermissionInterceptor.java View File

1
-package com.yunzhi.demo.interceptor;
2
-
3
-import com.alibaba.fastjson.JSONObject;
4
-import com.yunzhi.demo.common.JWTUtils;
5
-import com.yunzhi.demo.common.ResponseBean;
6
-import com.yunzhi.demo.common.StringUtils;
7
-import lombok.extern.slf4j.Slf4j;
8
-import org.springframework.stereotype.Component;
9
-import org.springframework.web.servlet.HandlerInterceptor;
10
-import org.springframework.web.servlet.ModelAndView;
11
-
12
-import javax.servlet.http.HttpServletRequest;
13
-import javax.servlet.http.HttpServletResponse;
14
-import java.io.IOException;
15
-
16
-
17
-@Slf4j
18
-@Component
19
-public class PermissionInterceptor implements HandlerInterceptor {
20
-
21
-    @Override
22
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
23
-        log.info("Request URI: {}", request.getRequestURI());
24
-
25
-        // JWT
26
-        String jws = JWTUtils.getToken(request);
27
-        if (StringUtils.isEmpty(jws)) {
28
-            responseTokenError(response, "鉴权失败, 请先进行登录操作");
29
-            return false;
30
-        }
31
-
32
-        try {
33
-            JWTUtils.verify(jws);
34
-        } catch (Exception e) {
35
-            log.error("鉴权失败: {}", e.getMessage());
36
-            responseTokenError(response, "鉴权失败, 请重新登录");
37
-            return false;
38
-        }
39
-
40
-        return true;
41
-    }
42
-
43
-    @Override
44
-    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object obj, ModelAndView mv) throws Exception {
45
-        // 刷新 TOKEN
46
-        String jws = JWTUtils.getToken(request);
47
-        JWTUtils.refresh(jws, response);
48
-    }
49
-
50
-    private void responseTokenError(HttpServletResponse response, String error) throws IOException {
51
-        response.addHeader("Content-type", "application/json");
52
-        response.getOutputStream().write(
53
-                JSONObject.toJSONBytes(
54
-                        ResponseBean.error(error, ResponseBean.ERROR_AUTH_FAIL)
55
-                ));
56
-    }
57
-}

+ 80
- 0
src/main/java/com/yunzhi/demo/log/MysqlAppender.java View File

1
+package com.yunzhi.demo.log;
2
+
3
+import ch.qos.logback.core.UnsynchronizedAppenderBase;
4
+import ch.qos.logback.core.db.ConnectionSource;
5
+import ch.qos.logback.core.encoder.Encoder;
6
+
7
+import java.sql.Connection;
8
+import java.sql.PreparedStatement;
9
+import java.util.Arrays;
10
+
11
+import static ch.qos.logback.core.db.DBHelper.closeStatement;
12
+
13
+public class MysqlAppender<E> extends UnsynchronizedAppenderBase<E> {
14
+    protected ConnectionSource connectionSource;
15
+    protected Encoder<E> encoder;
16
+    protected String app = "shigongli";
17
+
18
+    @Override
19
+    public void start() {
20
+        if (connectionSource == null) {
21
+            throw new IllegalStateException("MysqlAppender cannot function without a connection source");
22
+        }
23
+
24
+        super.start();
25
+    }
26
+
27
+    public ConnectionSource getConnectionSource() {
28
+        return connectionSource;
29
+    }
30
+
31
+    public void setConnectionSource(ConnectionSource connectionSource) {
32
+        this.connectionSource = connectionSource;
33
+    }
34
+
35
+    @Override
36
+    protected void append(E event) {
37
+        Connection connection = null;
38
+        PreparedStatement insertStatement = null;
39
+
40
+        try {
41
+            connection = connectionSource.getConnection();
42
+            connection.setAutoCommit(false);
43
+            insertStatement = connection.prepareStatement(getInsertSQL());
44
+
45
+            synchronized (this) {
46
+                byte[] logContent = this.encoder.encode(event);
47
+                insertStatement.setBytes(1, logContent);
48
+                insertStatement.execute();
49
+                closeStatement(insertStatement);
50
+            }
51
+
52
+            connection.commit();
53
+        } catch (Throwable sqle) {
54
+            addError("problem appending event", sqle);
55
+        }
56
+
57
+    }
58
+
59
+    public Encoder<E> getEncoder() {
60
+        return encoder;
61
+    }
62
+
63
+    public void setEncoder(Encoder<E> encoder) {
64
+        this.encoder = encoder;
65
+    }
66
+
67
+    @Override
68
+    public void stop() {
69
+        super.stop();
70
+    }
71
+
72
+    private String getInsertSQL() {
73
+        String tableName = "ta_"+app;
74
+        String[] columns = {"log"};
75
+        String[] signs = Arrays.stream(columns).map(x -> "?").toArray(String[]::new);
76
+        String sql = String.format("INSERT INTO %s (%s) values (%s)", tableName, String.join(",", columns), String.join(",", signs));
77
+//        System.out.println(sql);
78
+        return sql;
79
+    }
80
+}

+ 20
- 0
src/main/java/com/yunzhi/demo/service/IBaseService.java View File

1
+package com.yunzhi.demo.service;
2
+
3
+import com.baomidou.mybatisplus.extension.service.IService;
4
+
5
+import java.io.Serializable;
6
+
7
+public interface IBaseService<T> extends IService<T> {
8
+    /**
9
+     * 逻辑删除
10
+     * @param id
11
+     * @return
12
+     */
13
+    boolean removeLogicById(Serializable id);
14
+
15
+    int countBy(String column, Object value, boolean notDelete);
16
+
17
+    T getByButNot(String column, Object value, String col, Object val, boolean notDelete);
18
+
19
+    T getExistBy(String column, Object value, boolean normal, boolean notDelete);
20
+}

+ 54
- 0
src/main/java/com/yunzhi/demo/service/impl/BaseServiceImpl.java View File

1
+package com.yunzhi.demo.service.impl;
2
+
3
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
4
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
5
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
6
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
7
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
8
+import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
9
+import com.yunzhi.demo.service.IBaseService;
10
+
11
+import java.io.Serializable;
12
+
13
+public class BaseServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements IBaseService<T> {
14
+    @Override
15
+    public boolean removeLogicById(Serializable id) {
16
+
17
+        TableInfo tableInfo = SqlHelper.table(currentModelClass());
18
+        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
19
+        updateWrapper.set("state", -1)
20
+                .eq(tableInfo.getKeyColumn(), id);
21
+
22
+        return update(updateWrapper);
23
+    }
24
+
25
+    @Override
26
+    public int countBy(String column, Object value, boolean notDelete) {
27
+        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
28
+        queryWrapper.eq(column, value);
29
+        queryWrapper.gt(notDelete, "state", -1);
30
+
31
+        return count(queryWrapper);
32
+    }
33
+
34
+    @Override
35
+    public T getByButNot(String column, Object value, String col, Object val, boolean notDelete) {
36
+        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
37
+        queryWrapper.eq(column, value);
38
+        queryWrapper.ne(col, val);
39
+        queryWrapper.gt(notDelete, "state", -1);
40
+        queryWrapper.last("limit 1");
41
+
42
+        return getOne(queryWrapper);
43
+    }
44
+
45
+    @Override
46
+    public T getExistBy(String column, Object value, boolean normal, boolean notDelete) {
47
+        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
48
+        queryWrapper.eq(column, value);
49
+        queryWrapper.eq(normal, "state", 1);
50
+        queryWrapper.gt(notDelete, "state", -1);
51
+        queryWrapper.last("limit 1");
52
+        return getOne(queryWrapper);
53
+    }
54
+}

+ 26
- 0
src/main/java/com/yunzhi/demo/service/impl/ManagerServiceImpl.java View File

1
+package com.yunzhi.demo.service.impl;
2
+
3
+import com.yunzhi.demo.shiro.realms.manager.IManagerService;
4
+import org.springframework.stereotype.Service;
5
+
6
+import java.util.Set;
7
+
8
+@Service
9
+public class ManagerServiceImpl implements IManagerService {
10
+
11
+    @Override
12
+    public Boolean verify(String id) {
13
+        return null;
14
+    }
15
+
16
+    @Override
17
+    public Set<String> getRolesByLoginId(String id) {
18
+        return null;
19
+    }
20
+
21
+    @Override
22
+    public Set<String> getPermissionsLoginId(String id) {
23
+        return null;
24
+    }
25
+
26
+}

+ 76
- 0
src/main/java/com/yunzhi/demo/shiro/ShiroConfig.java View File

1
+package com.yunzhi.demo.shiro;
2
+
3
+import com.yunzhi.demo.shiro.filters.JWTFilter;
4
+import com.yunzhi.demo.shiro.matcher.JWTCredentialsMatcher;
5
+import com.yunzhi.demo.shiro.realms.manager.IManagerService;
6
+import com.yunzhi.demo.shiro.realms.manager.ManagerRealm;
7
+import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
8
+import org.apache.shiro.mgt.DefaultSubjectDAO;
9
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
10
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
11
+import org.springframework.beans.factory.annotation.Autowired;
12
+import org.springframework.beans.factory.annotation.Value;
13
+import org.springframework.context.annotation.Bean;
14
+import org.springframework.context.annotation.Configuration;
15
+
16
+import javax.servlet.Filter;
17
+import java.util.HashMap;
18
+import java.util.Map;
19
+
20
+@Configuration
21
+public class ShiroConfig {
22
+
23
+    @Autowired
24
+    IManagerService iManagerService;
25
+
26
+    @Value("${shiro.unauthorizedUrl}")
27
+    private String unauthorizedUrl;
28
+
29
+    @Value("#{${shiro.filterRuleMap}}")
30
+    private Map<String, String> filterRuleMap;
31
+
32
+    @Bean
33
+    public ManagerRealm managerRealm() {
34
+        ManagerRealm realm = new ManagerRealm();
35
+        realm.setManagerService(iManagerService);
36
+        realm.setCredentialsMatcher(new JWTCredentialsMatcher());
37
+        return realm;
38
+    }
39
+
40
+    @Bean("shiroFilterFactoryBean")
41
+    public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {
42
+        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
43
+
44
+        // 手动加入 JWTFilter
45
+        JWTFilter jwtFilter = new JWTFilter();
46
+        jwtFilter.setUnauthorizedUrl(unauthorizedUrl);
47
+
48
+        Map<String, Filter> filterMap = new HashMap<>();
49
+        filterMap.put("jwt", jwtFilter);
50
+        factoryBean.setFilters(filterMap);
51
+
52
+        factoryBean.setSecurityManager(securityManager);
53
+        factoryBean.setUnauthorizedUrl(unauthorizedUrl);
54
+
55
+        factoryBean.setFilterChainDefinitionMap(filterRuleMap);
56
+        return factoryBean;
57
+    }
58
+
59
+    @Bean("securityManager")
60
+    public DefaultWebSecurityManager securityManager() {
61
+        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
62
+        //  Use your own realm
63
+        manager.setRealm(managerRealm());
64
+
65
+        /*
66
+         * 禁用 session
67
+         */
68
+        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
69
+        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
70
+        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
71
+        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
72
+        manager.setSubjectDAO(subjectDAO);
73
+
74
+        return manager;
75
+    }
76
+}

+ 83
- 0
src/main/java/com/yunzhi/demo/shiro/filters/JWTFilter.java View File

1
+package com.yunzhi.demo.shiro.filters;
2
+
3
+import com.yunzhi.demo.shiro.utils.JWTToken;
4
+import com.yunzhi.demo.shiro.utils.JWTUtil;
5
+import org.apache.shiro.authc.AuthenticationToken;
6
+import org.apache.shiro.subject.Subject;
7
+import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
8
+import org.apache.shiro.web.util.WebUtils;
9
+import org.slf4j.Logger;
10
+import org.slf4j.LoggerFactory;
11
+
12
+import javax.servlet.ServletRequest;
13
+import javax.servlet.ServletResponse;
14
+import javax.servlet.http.HttpServletResponse;
15
+import java.io.IOException;
16
+
17
+public class JWTFilter extends AuthenticatingFilter {
18
+
19
+    private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
20
+
21
+    public final static String JWT_HEADER = "Authorization";
22
+
23
+    // 20 分钟刷新一次 token
24
+    private final static long REFRESH_MILLS = 20 * 60 * 1000;
25
+
26
+    private String unauthorizedUrl;
27
+    public void setUnauthorizedUrl(String unauthorizedUrl) {
28
+        this.unauthorizedUrl = unauthorizedUrl;
29
+    }
30
+
31
+    @Override
32
+    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
33
+        String authorization = WebUtils.toHttp(servletRequest).getHeader(JWT_HEADER);
34
+        if (authorization == null || "".equals(authorization)) {
35
+            throw new Exception("token不能为空");
36
+        }
37
+
38
+        return new JWTToken(authorization);
39
+    }
40
+
41
+    @Override
42
+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
43
+        boolean allowed = false;
44
+        try {
45
+            allowed = executeLogin(request, response);
46
+        } catch (Exception e) {
47
+            response401(request, response);
48
+        }
49
+
50
+        return allowed;
51
+//        return allowed || super.isPermissive(mappedValue);
52
+    }
53
+
54
+    @Override
55
+    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
56
+        return false;
57
+    }
58
+
59
+    // 主要用来刷新 token
60
+    @Override
61
+    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
62
+        String originToken = token.getPrincipal().toString();
63
+
64
+        long diff = System.currentTimeMillis() - JWTUtil.getExpDate(originToken).getTime();
65
+        if (diff >= REFRESH_MILLS) {
66
+            HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
67
+            httpServletResponse.setHeader(JWT_HEADER, JWTUtil.refresh(originToken));
68
+        }
69
+
70
+        return true;
71
+    }
72
+
73
+    /**
74
+     *Jump illegal request to / 401
75
+     */
76
+    private void response401(ServletRequest request, ServletResponse response) {
77
+        try {
78
+            WebUtils.toHttp(response).sendRedirect(unauthorizedUrl);
79
+        } catch (IOException e) {
80
+            LOGGER.error(e.getMessage());
81
+        }
82
+    }
83
+}

+ 14
- 0
src/main/java/com/yunzhi/demo/shiro/matcher/JWTCredentialsMatcher.java View File

1
+package com.yunzhi.demo.shiro.matcher;
2
+
3
+import com.yunzhi.demo.shiro.utils.JWTUtil;
4
+import org.apache.shiro.authc.AuthenticationInfo;
5
+import org.apache.shiro.authc.AuthenticationToken;
6
+import org.apache.shiro.authc.credential.CredentialsMatcher;
7
+
8
+public class JWTCredentialsMatcher implements CredentialsMatcher {
9
+    @Override
10
+    public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
11
+        String token = authenticationToken.getCredentials().toString();
12
+        return JWTUtil.verify(token);
13
+    }
14
+}

+ 31
- 0
src/main/java/com/yunzhi/demo/shiro/realms/manager/IManagerService.java View File

1
+package com.yunzhi.demo.shiro.realms.manager;
2
+
3
+import java.util.Set;
4
+
5
+/**
6
+ *
7
+ */
8
+public interface IManagerService {
9
+
10
+    /**
11
+     * 校验用户状态
12
+     * @param id
13
+     * @return
14
+     */
15
+    Boolean verify(String id);
16
+
17
+    /**
18
+     * 获取用户角色
19
+     * @param id
20
+     * @return
21
+     */
22
+    Set<String> getRolesByLoginId(String id);
23
+
24
+    /**
25
+     * 获取用户权限
26
+     * @param id
27
+     * @return
28
+     */
29
+    Set<String> getPermissionsLoginId(String id);
30
+
31
+}

+ 55
- 0
src/main/java/com/yunzhi/demo/shiro/realms/manager/ManagerRealm.java View File

1
+package com.yunzhi.demo.shiro.realms.manager;
2
+
3
+import com.yunzhi.demo.shiro.utils.JWTToken;
4
+import com.yunzhi.demo.shiro.utils.JWTUtil;
5
+import org.apache.shiro.authc.AuthenticationException;
6
+import org.apache.shiro.authc.AuthenticationInfo;
7
+import org.apache.shiro.authc.AuthenticationToken;
8
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
9
+import org.apache.shiro.authz.AuthorizationInfo;
10
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
11
+import org.apache.shiro.realm.AuthorizingRealm;
12
+import org.apache.shiro.subject.PrincipalCollection;
13
+
14
+import java.util.Set;
15
+
16
+public class ManagerRealm extends AuthorizingRealm {
17
+
18
+    IManagerService iManagerService;
19
+
20
+    public void setManagerService(IManagerService iManagerService) {
21
+        this.iManagerService = iManagerService;
22
+    }
23
+
24
+    @Override
25
+    public boolean supports(AuthenticationToken token) {
26
+        return token instanceof JWTToken;
27
+    }
28
+
29
+    @Override
30
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
31
+        // 获取用户角色,权限
32
+        String token = (String) principalCollection.getPrimaryPrincipal();
33
+        String loginId = JWTUtil.getLoginId(token);
34
+        Set<String> roles = iManagerService.getRolesByLoginId(loginId);
35
+        Set<String> permissions = iManagerService.getPermissionsLoginId(loginId);
36
+
37
+        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
38
+        simpleAuthorizationInfo.setStringPermissions(permissions);
39
+        simpleAuthorizationInfo.setRoles(roles);
40
+        return simpleAuthorizationInfo;
41
+    }
42
+
43
+    @Override
44
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
45
+        String token = (String) authenticationToken.getPrincipal();
46
+        String loginId = JWTUtil.getLoginId(token);
47
+
48
+        if (!iManagerService.verify(loginId)) {
49
+            throw new AuthenticationException("User is abnormal");
50
+        }
51
+
52
+        // 交给 AuthenticatingRealm 使用 CredentialsMatcher 行校验
53
+        return new SimpleAuthenticationInfo(token, token, getName());
54
+    }
55
+}

+ 23
- 0
src/main/java/com/yunzhi/demo/shiro/utils/JWTToken.java View File

1
+package com.yunzhi.demo.shiro.utils;
2
+
3
+import org.apache.shiro.authc.AuthenticationToken;
4
+
5
+public class JWTToken implements AuthenticationToken {
6
+
7
+    //Key
8
+    private String token;
9
+
10
+    public JWTToken(String token) {
11
+        this.token = token;
12
+    }
13
+
14
+    @Override
15
+    public Object getPrincipal() {
16
+        return token;
17
+    }
18
+
19
+    @Override
20
+    public Object getCredentials() {
21
+        return token;
22
+    }
23
+}

+ 65
- 0
src/main/java/com/yunzhi/demo/shiro/utils/JWTUtil.java View File

1
+package com.yunzhi.demo.shiro.utils;
2
+
3
+import com.auth0.jwt.JWT;
4
+import com.auth0.jwt.algorithms.Algorithm;
5
+import com.auth0.jwt.exceptions.JWTDecodeException;
6
+import com.auth0.jwt.interfaces.DecodedJWT;
7
+
8
+import java.util.Date;
9
+
10
+/**
11
+ * 一个通用版本的 JWT
12
+ */
13
+public class JWTUtil {
14
+
15
+    // 默认过期时间 1 小时
16
+    private static final long EXPIRE_TIME = 60 * 60 * 1000;
17
+
18
+    public static String getLoginId(String token) {
19
+        try {
20
+            DecodedJWT jwt = JWT.decode(token);
21
+            return jwt.getSubject();
22
+        } catch (JWTDecodeException e) {
23
+            return null;
24
+        }
25
+    }
26
+
27
+    public static Date getExpDate(String token) {
28
+        try {
29
+            DecodedJWT jwt = JWT.decode(token);
30
+            return jwt.getExpiresAt();
31
+        } catch (JWTDecodeException e) {
32
+            return null;
33
+        }
34
+    }
35
+
36
+    public static String sign(String loginId, String secret) {
37
+        Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
38
+        Algorithm algorithm = Algorithm.HMAC256(secret);
39
+
40
+        return JWT.create()
41
+                .withSubject(loginId)
42
+                .withExpiresAt(date)
43
+                .withClaim("secret", secret)
44
+                .sign(algorithm);
45
+    }
46
+
47
+    public static String refresh(String token) throws Exception {
48
+        DecodedJWT jwt = JWT.decode(token);
49
+        String loginId = jwt.getSubject();
50
+        String secret = jwt.getClaim("secret").asString();
51
+
52
+        return sign(loginId, secret);
53
+    }
54
+
55
+    public static boolean verify(String token) {
56
+        try {
57
+            JWT.decode(token);
58
+            return true;
59
+        } catch (Exception e) {
60
+            e.printStackTrace();
61
+            return false;
62
+        }
63
+    }
64
+
65
+}

+ 3
- 3
src/main/resources/application-dev.yml View File

5
       max-file-size: 10MB
5
       max-file-size: 10MB
6
       max-request-size: 50MB
6
       max-request-size: 50MB
7
   datasource:
7
   datasource:
8
-    url: jdbc:mysql://rm-uf6z3z6jq11x653d77o.mysql.rds.aliyuncs.com:3306/niucai?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
9
-    username: niucai
10
-    password: 1qaz#EDC
8
+    url: jdbc:mysql://rm-uf6z3z6jq11x653d77o.mysql.rds.aliyuncs.com:3306/dianyang_colmo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
9
+    username: dianyang_colmo
10
+    password: dianyang_colmo@ABC123
11
 
11
 
12
 ###
12
 ###
13
 logging:
13
 logging:

+ 4
- 3
src/main/resources/application-prod.yml View File

5
       max-file-size: 10MB
5
       max-file-size: 10MB
6
       max-request-size: 50MB
6
       max-request-size: 50MB
7
   datasource:
7
   datasource:
8
-    url: jdbc:mysql://rm-uf6z3z6jq11x653d77o.mysql.rds.aliyuncs.com:3306/niucai?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
9
-    username: niucai
10
-    password: 1qaz#EDC
8
+    url: jdbc:mysql://rm-uf6z3z6jq11x653d77o.mysql.rds.aliyuncs.com:3306/dianyang_colmo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
9
+    username: dianyang_colmo
10
+    password: dianyang_colmo@ABC123
11
+

+ 22
- 10
src/main/resources/application.yml View File

5
     context-path: /api
5
     context-path: /api
6
 
6
 
7
 ###
7
 ###
8
-interceptor:
9
-  permission:
10
-    enable: true
11
-    include-paths: /**
12
-    exclude-paths:
13
-      - /login
14
-      - /logout
15
-      - /swagger-ui/**
16
-      - /swagger-resources/**
17
-      - /v2/**
8
+shiro:
9
+  enabled: true
10
+  unauthorizedUrl: /api/401
11
+  filterRuleMap: '{
12
+    "[/api/admin/**]": "jwt",
13
+    "[/**]": "anon"
14
+  }'
18
 
15
 
19
 ###
16
 ###
20
 mybatis-plus:
17
 mybatis-plus:
23
     call-setters-on-nulls: true
20
     call-setters-on-nulls: true
24
   mapper-locations: classpath:mapper/**/*.xml
21
   mapper-locations: classpath:mapper/**/*.xml
25
 
22
 
23
+###
24
+sms:
25
+  captcha:
26
+    code: SMS_207555188
27
+    sign: 云致科技
28
+
29
+###
30
+yz:
31
+  sms:
32
+    ## 可以任意名称
33
+    appid: state-grid-training
34
+    api: http://sms.njyunzhi.com/sms
35
+    ## 帮助文档
36
+    help: http://sms.njyunzhi.com/help
37
+
26
 ###
38
 ###
27
 aliyun:
39
 aliyun:
28
   accessKeyId: LTAI4FdMQNh1xUoiqqbKJ15J
40
   accessKeyId: LTAI4FdMQNh1xUoiqqbKJ15J

+ 31
- 0
src/main/resources/logback.xml.bak View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<configuration>
3
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
4
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
5
+            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
6
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
7
+        </encoder>
8
+    </appender>
9
+    <appender name="LOGDB" class="com.yunzhi.dianyang.log.MysqlAppender">
10
+        <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
11
+            <driverClass>com.mysql.cj.jdbc.Driver</driverClass>
12
+            <url>jdbc:mysql://rm-uf6z3z6jq11x653d77o.mysql.rds.aliyuncs.com:3306/yz_questions</url>
13
+            <user>yz_questions</user>
14
+            <password>questions@1234</password>
15
+        </connectionSource>
16
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
17
+            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
18
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
19
+        </encoder>
20
+    </appender>
21
+
22
+    <logger name="com.apache.ibatis" level="TRACE"/>
23
+    <logger name="java.sql.Connection" level="DEBUG"/>
24
+    <logger name="java.sql.Statement" level="DEBUG"/>
25
+    <logger name="java.sql.PreparedStatement" level="DEBUG"/>
26
+
27
+    <root level="INFO">
28
+        <appender-ref ref="STDOUT" />
29
+        <appender-ref ref="LOGDB" />
30
+    </root>
31
+</configuration>