1
8 小时以前 5ef6c105aca5bd7c0c63ce3240fbe82c2e07e8f7
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
package com.vincent.rsf.openApi.security.filter;
 
import com.vincent.rsf.openApi.entity.constant.Constants;
import com.vincent.rsf.openApi.security.service.AppAuthService;
import com.vincent.rsf.openApi.security.utils.TokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.utils.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
 
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
 
/**
 * AppId和AppSecret认证过滤器
 * 
 * 用于验证请求头中的AppId和AppSecret
 * 
 * @author vincent
 * @since 2026-01-05
 */
@Slf4j
@Component
@Order(1)
public class AppIdAuthenticationFilter extends OncePerRequestFilter {
 
    @Resource
    private AppAuthService appAuthService;
 
 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 
            throws ServletException, IOException {
 
        String requestURI = request.getRequestURI();
        
        // 检查是否为认证请求(如获取token)
        if (isAuthRequest(requestURI)) {
            // 对于认证请求,允许通过
            filterChain.doFilter(request, response);
            return;
        }
 
        // rsf-server本机调用直通,不需要Token
        if (isRequestFromRsfServer(request)) {
            request.setAttribute(Constants.REQUEST_ATTR_APP_ID, "rsf-server");
            filterChain.doFilter(request, response);
            return;
        }
 
        String authHeader = request.getHeader(Constants.HEADER_AUTHORIZATION);
        if (authHeader != null) {
            String token = TokenUtils.extractTokenFromHeader(authHeader);
            if (token != null && TokenUtils.validateTokenTime(token)) {
                // Token时间认证成功,认证AppId和AppSecret
                String tokenAppId = TokenUtils.getAppIdFromToken(token);
                String tokenAppSecret = TokenUtils.getSecretFromToken(token);
                if (StringUtils.isBlank(tokenAppId) || StringUtils.isBlank(tokenAppSecret)
                        || !appAuthService.validateApp(tokenAppId, tokenAppSecret)) {
                    log.warn("Token验证失败");
                    sendErrorResponse(response, Integer.parseInt(Constants.UNAUTHENTICATED_CODE), "认证失败,请提供有效的Token");
                    return;
                } else {
                    request.setAttribute(Constants.REQUEST_ATTR_APP_ID, tokenAppId);
                }
            } else {
                log.warn("Token验证失败或缺失");
                sendErrorResponse(response, Integer.parseInt(Constants.UNAUTHENTICATED_CODE), "认证失败,请提供有效的Token");
                return;
            }
        } else {
            log.warn("缺少Token认证信息");
            sendErrorResponse(response, Integer.parseInt(Constants.UNAUTHENTICATED_CODE), "认证失败,请提供有效的Token");
            return;
        }
 
        filterChain.doFilter(request, response);
    }
 
    /**
     * 发送错误响应
     * 
     * @param response HTTP响应
     * @param code 错误码
     * @param message 错误消息
     * @throws IOException
     */
    private void sendErrorResponse(HttpServletResponse response, int code, String message) throws IOException {
        response.setStatus(code);
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write("{\"code\": \"" + code + "\", \"msg\": \"" + message + "\", \"data\": null}");
        writer.flush();
    }
 
    /**
     * 检查是否为认证请求(不需要认证的请求)
     * 
     * @param requestURI 请求URI
     * @return 是否为认证请求
     */
    private boolean isAuthRequest(String requestURI) {
        return requestURI.contains("/getToken");
//               || requestURI.contains("/auth/validate") ||
//               requestURI.contains("/auth/login");
    }
 
    /**
     * 判断是否来自rsf-server的内部请求
     * 约定:同机部署时,rsf-server通过127.0.0.1/::1访问open-api
     */
    private boolean isRequestFromRsfServer(HttpServletRequest request) {
        String remoteAddr = request.getRemoteAddr();
        if (StringUtils.isBlank(remoteAddr)) {
            return false;
        }
 
        if ("127.0.0.1".equals(remoteAddr) || "::1".equals(remoteAddr) || "0:0:0:0:0:0:0:1".equals(remoteAddr)) {
            return true;
        }
 
        try {
            InetAddress address = InetAddress.getByName(remoteAddr);
            return address.isLoopbackAddress() || address.isAnyLocalAddress();
        } catch (UnknownHostException e) {
            return false;
        }
    }
 
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String requestURI = request.getRequestURI();
        
        // 不过滤认证相关请求和公开接口
        return requestURI.contains("/auth/") || 
               requestURI.contains("/public/") ||
               requestURI.contains("/doc.html") ||
               requestURI.contains("/swagger") ||
               requestURI.contains("/webjars") ||
               requestURI.contains("/v2/api-docs") ||
               requestURI.contains("/v3/api-docs");
    }
 
}