如何序列化 java.security.Principal



>我写了这段代码:

@RestController
public class UserController {
private final static Logger LOGGER = LoggerFactory.getLogger(UserController.class);
@RequestMapping(path = "/", produces = "application/json")
public @ResponseBody Principal getUser(HttpServletRequest request) throws Exception {
try {
Principal principal = request.getUserPrincipal();
LOGGER.debug("User found" + principal.toString());
return principal;
} 
catch (Exception e) {
LOGGER.debug("User not found : " + e.getMessage());
throw e;
}
}
}

但它抛出:

java.lang.IllegalStateException: getOutputStream() 已经 呼吁作出此回应

如何序列化该对象?是什么使对象可序列化为 Spring Boot?在执行过程中,实际的对象类型是Principalorg.apache.catalina.realm.GenericPrincipal实现

根据要求,以下是完整的堆栈跟踪:

#ERROR#org.apache.catalina.core.ContainerBase.[卡塔琳娜]。[本地主机]。[/loggedinusertest].[dispatcherServlet]##anonymous#https-jsse-nio-8041-exec-5#na#ab54cfe76#loggedinusertest#web#ab54cfe76#na#na#na#na#Servlet.service() for servlet [dispatcherServlet] 抛出异常 java.lang.IllegalStateException: getOutputStream() 已经 呼吁在 org.apache.catalina.connector.Response.getWriter(Response.java:624) 在org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:211) 在 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView.render(ErrorMvcAutoConfiguration.java:218) 在 org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1257) 在 org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037) 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) 在 org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) 在org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:112) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:728) 在 org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:470) 在 org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:395) 在 org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:316) 在 org.springframework.boot.web.support.ErrorPageFilter.handleErrorStatus(ErrorPageFilter.java:153) 在 org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:121) 在 org.springframework.boot.web.support.ErrorPageFilter.access$000(ErrorPageFilter.java:61) 在org.springframework.boot.web.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:94) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:112) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) 在 com.sap.core.connectivity.jco.session.ext.RequestTracker.invoke(RequestTracker.java:55) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:610) 在 com.sap.cloud.runtime.impl.bridge.security.AbstractAuthenticator.invoke(AbstractAuthenticator.java:206) 在org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) 在 org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650) 在 org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650) 在 com.sap.core.tenant.valve.TenantValidationValve.invokeNextValve(TenantValidationValve.java:182) 在 com.sap.core.tenant.valve.TenantValidationValve.invoke(TenantValidationValve.java:97) 在 com.sap.js.statistics.tomcat.valve.RequestTracingValve.callNextValve(RequestTracingValve.java:113) 在 com.sap.js.statistics.tomcat.valve.RequestTracingValve.invoke(RequestTracingValve.java:59) 在 com.sap.core.js.monitoring.tomcat.valve.RequestTracingValve.invoke(RequestTracingValve.java:27) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) 在org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) 在 org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) 在 org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) 在 org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471) 在 org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 在 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:836)

通过在 Web API 中公开Principal实例(例如来自 Apache Tomcat 的GenericPrincipal实例),您最终可能会泄露一些您不打算泄露的敏感细节。

更好的方法是创建 DTO,然后仅将要公开的主要详细信息映射到此 DTO。


尽管存在安全漏洞,但让我澄清一下序列化本身可能存在的问题。

如果创建GenericPrincipal的实例,然后尝试直接使用ObjectMapper将其序列化为 JSON,则会看到它不会成功:

ObjectMapper mapper = new ObjectMapper();
Principal principal = new GenericPrincipal("john.doe", "secret", Arrays.asList("admin"));
String json = mapper.writeValueAsString(principal);

例外情况是:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: org.apache.catalina.realm.GenericPrincipal["userPrincipal"])

如果您检查GenericPrincipal源代码,您将看到一个userPrincipal字段:

protected final Principal userPrincipal;

好吧,您可以尝试使用混合注释,但这可能不值得。只需创建一个 DTO 并仅公开您需要的内容。

相关内容

最新更新