xiaoyong931011
2020-11-30 7ae23e17d8e90dc634f3f86e2eee209cbacaace3
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
155
156
157
package com.xcong.excoin.configurations.security;
 
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.contants.AppContants;
import com.xcong.excoin.common.exception.GlobalException;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.common.system.bean.LoginUserBean;
import com.xcong.excoin.configurations.properties.ApplicationProperties;
import com.xcong.excoin.configurations.properties.SecurityProperties;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.utils.RedisUtils;
import com.xcong.excoin.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
 
/**
 * @author wzy
 * @date 2020-05-12
 **/
@Slf4j
public class TokenFilter extends GenericFilterBean {
 
    private final ApplicationProperties applicationProperties = SpringContextHolder.getBean(ApplicationProperties.class);
 
    private final SecurityProperties securityProperties = SpringContextHolder.getBean(SecurityProperties.class);
 
    private final RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String token = resolveTokenOutCenter(request);
 
        if (!AppContants.TIME_OUT.equals(token)) {
            if (StrUtil.isNotBlank(token)) {
                String redisKey = "";
                // 根据user-agent判断pc端还是app端
                if (LoginUserUtils.isBrowser(request)) {
                    redisKey = token;;
                } else {
                    redisKey = token;;
                }
 
                String loginStr = (String) redisUtils.get(redisKey);
                if (StrUtil.isNotBlank(loginStr)) {
                    MemberEntity loginUser = JSONObject.parseObject(loginStr, MemberEntity.class);
                    Authentication authentication = new UsernamePasswordAuthenticationToken(loginUser, token, new ArrayList<>());
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                } else {
                    log.info("token无法查询:{}", token);
                    SecurityContextHolder.clearContext();
                }
            } else {
//                log.info("token为空:{}", request.getRequestURI());
                SecurityContextHolder.clearContext();
            }
        } else {
            response.setHeader("TimeOut", AppContants.TIME_OUT);
            SecurityContextHolder.clearContext();
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
    
    /**
     * 解析前端传来的token,md5加密后的地址_设备iD_/api
     *
     * @param request
     * @return
     */
    private String resolveTokenOutCenter(HttpServletRequest request) {
        try {
            String bearerToken = request.getHeader(AppContants.TOKEN_HEADER);
            //获取请求的完整路径
            StringBuffer requestURL = request.getRequestURL();
            
            if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(AppContants.TOKEN_START_WITH)) {
                // 去掉令牌前缀
                String rsaToken = bearerToken.replace(AppContants.TOKEN_START_WITH, "");
                RSA rsa = new RSA(securityProperties.getPrivateKey(), null);
                String decryptStr = rsa.decryptStr(rsaToken, KeyType.PrivateKey);
                String[] tokens = StrUtil.split(decryptStr, "_");
 
                if (StrUtil.isNotEmpty(requestURL) && requestURL.toString().contains(tokens[2])) {
                    return tokens[0];
                } else {
//                    log.info("前面token为{}", tokens[0]);
//                    log.info("时间为:{}, 当前时间为:{}", tokens[1], System.currentTimeMillis());
                    return AppContants.TIME_OUT;
                }
            }
//            log.info("bearerToken---->{}", bearerToken);
        } catch (Exception e) {
            log.error("#解析token异常#", e);
            return null;
        }
        return null;
    }
 
    /**
     * 解析前端传来的token,先去掉Bearer,在rsa解密得到token_time,返回token,并判断time与当前是否在5s内
     *
     * @param request
     * @return
     */
    private String resolveToken(HttpServletRequest request) {
        try {
            String bearerToken = request.getHeader(AppContants.TOKEN_HEADER);
            if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(AppContants.TOKEN_START_WITH)) {
                // 去掉令牌前缀
                String rsaToken = bearerToken.replace(AppContants.TOKEN_START_WITH, "");
                RSA rsa = new RSA(securityProperties.getPrivateKey(), null);
                String[] tokens = StrUtil.split(rsa.decryptStr(rsaToken, KeyType.PrivateKey), "_");
 
                if (verifyTokenExpired(Long.parseLong(tokens[1]))) {
                    return tokens[0];
                } else {
//                    log.info("前面token为{}", tokens[0]);
//                    log.info("时间为:{}, 当前时间为:{}", tokens[1], System.currentTimeMillis());
                    return AppContants.TIME_OUT;
                }
            }
//            log.info("bearerToken---->{}", bearerToken);
        } catch (Exception e) {
            log.error("#解析token异常#", e);
            return null;
        }
        return null;
    }
 
    private Boolean verifyTokenExpired(Long time) {
        boolean isDebug = applicationProperties.isDebug();
        if (!isDebug) {
            long currentTime = System.currentTimeMillis();
            return currentTime - time <= 30000;
        }
        return true;
    }
}