CXF 支持 JAX-RS 規範實現 RESTful 服務,結合 Spring Security / JWT 實現 Token 權限控制。
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.5.0</version>
</dependency>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<jaxrs:server address="/services">
<jaxrs:serviceBeans>
<ref bean="userService"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider"/>
<ref bean="authFilter"/> <!-- Token 驗證過濾器 -->
</jaxrs:providers>
</jaxrs:server>
@Provider
@Priority(Priorities.AUTHENTICATION)
public class JwtAuthFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
return;
}
String token = authHeader.substring("Bearer ".length());
try {
Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
// 將用戶信息/角色放入 SecurityContext
requestContext.setSecurityContext(new SecurityContext() {
@Override public Principal getUserPrincipal() { return () -> claims.getSubject(); }
@Override public boolean isUserInRole(String role) { return claims.get("roles", List.class).contains(role); }
@Override public boolean isSecure() { return requestContext.getUriInfo().getRequestUri().getScheme().equals("https"); }
@Override public String getAuthenticationScheme() { return "JWT"; }
});
} catch (JwtException e) {
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Token 無效/過期").build());
}
}
}
引入 cxf-spring-boot-starter-jwt 或手動配置 SecurityConfig,使用 @PreAuthorize("hasRole('ADMIN')") 註解保護資源方法。
JaxRsProxyFactoryBean factory = new JaxRsProxyFactoryBean();
factory.setServiceClass(UserService.class);
factory.setAddress("https://localhost:8080/api/services");
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
// 添加 Token
factory.getOutInterceptors().add(new AbstractPhaseInterceptor(Phase.PREPARE_SEND) {
@Override public void handleMessage(Message message) {
Map> headers = new HashMap<>();
headers.put(HttpHeaders.AUTHORIZATION, Collections.singletonList("Bearer " + token));
message.put(Message.PROTOCOL_HEADERS, headers);
}
});
UserService client = factory.create(UserService.class);
client.getUser(123);
@Path, @GET, @Produces) 開發體驗佳。WebClient) 無需服務端介面 Jar 包。CXF + JAX-RS + JWT 是 Java 輕量級 REST 服務的黃金組合。