1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
package io.github.lyr2000.dissertation.components;
import cn.hutool.core.util.StrUtil;
import io.github.lyr2000.common.dto.Result;
import io.github.lyr2000.common.enums.DefaultApiCode;
import io.github.lyr2000.common.shiro.JwtResult;
import io.github.lyr2000.common.shiro.config.ShiroConstant;
import io.github.lyr2000.common.shiro.config.ShiroCustomProperties;
import io.github.lyr2000.common.shiro.entity.JwtToken;
import io.github.lyr2000.common.shiro.filter.JwtFilter;
import io.github.lyr2000.common.shiro.util.JwtUtil;
import io.github.lyr2000.common.shiro.util.ShiroWebUtil;
import io.github.lyr2000.common.util.WebUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.annotation.PostConstruct;
import javax.persistence.Access;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
/**
* @author lyr
* @description 跨域配置
* @create 2021-11-09 19:34
*/
@Slf4j
// @Component
@Accessors(chain = true)
public class ShiroHttpAuthenticationFilter extends JwtFilter {
private final ShiroCustomProperties shiroCustomProperties;
private final JwtUtil jwtUtil;
@Setter
private ProfileUtil profileUtil;
public ShiroHttpAuthenticationFilter(ShiroCustomProperties shiroCustomProperties, JwtUtil jwtUtil) {
super(shiroCustomProperties, jwtUtil);
this.shiroCustomProperties = shiroCustomProperties;
this.jwtUtil = jwtUtil;
}
/**
* 重写 jwtFilter 解决跨域问题
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", "http://localhost:3000"); //标识允许哪个域到请求,直接修改成请求头的域
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); //标识允许哪个域到请求,直接修改成请求头的域
httpServletResponse.setHeader("Access-Control-Allow-Methods", httpServletRequest.getMethod());//标识允许的请求方法
// 响应首部 Access-Control-Allow-Headers 用于 preflight request (预检请求)中,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。修改为请求首部
//参考:https://cloud.tencent.com/developer/section/1189900
// httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Content-Length, Authorization, Accept, X-Requested-With , token");
log.info("request.. {}",httpServletRequest.getHeader("Origin"));
//给option请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
// log.info("options is OK");
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
/**
* 获取用户请求头 或者参数的 token
* @param request
* @return
*/
private String getRealToken(HttpServletRequest request) {
if (profileUtil == null) {
return null;
}
String token = null;
token = request.getHeader("token");
if (token == null) {
token = request.getParameter("token");
}
// log.info("profile active = {}",profileUtil.getActiveProfile());
if ("test".equals(profileUtil.getActiveProfile())) {
//如果 token == debug 或者test ,说明是测试,假设用户ID 是 1 ,返回
if ("test".equalsIgnoreCase(token) || "debug".equalsIgnoreCase(token)) {
//假设用户ID 是 1
Map<String,Object> map = new HashMap<>();
map.put("id",1);
return jwtUtil.sign(map, Duration.ofDays(1).toMillis());
}
return token;
}
return token;
}
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
// String token = WebUtils.toHttp(request).getHeader(shiroCustomProperties.getTokenHeader());
//获取传递来 的 token
String token = getRealToken((HttpServletRequest) request);
if (null == token || StrUtil.isBlank(token)) {
log.info("token is null ,url = {}",WebUtils.toHttp(request).getRequestURI());
// log.info("丢出异常");
// throw new ApiException(DefaultApiCode.NO_TOKEN);
ShiroWebUtil.renderJson((HttpServletResponse) response, Result.of(DefaultApiCode.NO_TOKEN,"请登录验证"));
return false;
}
try {
JwtToken jwtToken = jwtUtil.decodeJwtToken(token);
JwtResult result = jwtToken.getResult();
if(result == null || result == JwtResult.Fail) {
ShiroWebUtil.renderJson((HttpServletResponse) response, Result.from(DefaultApiCode.TokenCheckFail));
return false;
}else if (result == JwtResult.OVERDUE) {
WebUtil.renderJson((HttpServletResponse) response, Result.from(DefaultApiCode.TOKEN_EXPIRED));
return false;
}
//
request.setAttribute(ShiroConstant.requestAttrName,jwtToken);
//执行登录逻辑
getSubject(request,response).login(jwtToken);
return true;
}catch (Exception e) {
log.error("msg = {}",e.getMessage());
}
return false;
}
}
|