kongzy
2024-01-29 983bdb5b89932b38d08a11ad1eed6ea89d1597e1
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
package com.gkhy.assess.framework.shiro.filter;
 
import com.alibaba.fastjson.JSONObject;
import com.gkhy.assess.common.api.CommonResult;
import com.gkhy.assess.common.api.ResultCode;
import com.gkhy.assess.common.exception.ApiException;
import com.gkhy.assess.common.utils.JwtTokenUtil;
import com.gkhy.assess.framework.shiro.JwtToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
 
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Date;
 
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {
 
    /**
     * 默认开启跨域设置(使用单体)
     * 微服务情况下,此属性设置为false
     */
    private boolean allowOrigin = true;
 
    public JwtFilter(){}
 
    public JwtFilter(boolean allowOrigin){
        this.allowOrigin=allowOrigin;
    }
 
    /**
     * 前置拦截处理
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        //servlet请求与响应的转换
        HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
        if(allowOrigin){
            this.fillCorsHeader(WebUtils.toHttp(request), WebUtils.toHttp(response));
        }
        //跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
        if(httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())){
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }
 
 
 
    /**
     * 过滤器拦截请求的入口方法,所有请求都会进入该方法
     * 返回true则允许访问
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        try{
            //检测header里的JWT Token内容是否正确,尝试使用token进行登录
            this.executeLogin(request,response);
            return true;
        } catch (Exception e){ //未找到token
            log.error(e.getMessage());
            JwtTokenUtil.responseError(response,e.getMessage());
        }
        return false;
    }
 
    /**
     * 身份验证,检查JWT token是否合法
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String jwtToken = httpServletRequest.getHeader(JwtTokenUtil.USER_LOGIN_TOKEN);
        JwtToken token=new JwtToken(jwtToken);
        Subject subject = getSubject(request,response);
        subject.login(token);
        return true;
    }
 
 
    /**
     * isAccessAllowed()方法返回false,会进入该方法,表示拒绝访问
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        httpServletResponse.setStatus(HttpStatus.OK.value());
 
        PrintWriter writer = httpServletResponse.getWriter();
 
        writer.write(JSONObject.toJSONString(CommonResult.failed(ResultCode.UNAUTHORIZED)));
 
        return false;
    }
 
 
    //跨域请求的解决方案之一
    protected void fillCorsHeader(HttpServletRequest request, HttpServletResponse response){
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, request.getHeader(HttpHeaders.ORIGIN));
        // 允许客户端请求方法
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,OPTIONS,HEAD,PUT,DELETE");
        // 允许客户端提交的Header
        String requestHeaders = request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
        if (StringUtils.isNotEmpty(requestHeaders)) {
            response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders);
        }
        // 允许客户端携带凭证信息(是否允许发送Cookie)
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
    }
 
}