actuator的原理

朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 数分钟之内即可在任何应用程序中对用户进行身份验证,管理和保护。

您是否曾与Spring Boot Actuator合作? 这是一个非常有用的库,可帮助您监视应用程序的运行状况以及与应用程序的交互-非常适合投入生产! Spring Boot Actuator包含一个内置端点,该端点用于跟踪对您的应用程序的HTTP调用-对监视OpenID Connect(OIDC)请求非常有用-但不幸的是,默认实现不跟踪主体内容。 在这篇文章中,我将向您展示如何扩展httptrace端点以捕获内容并跟踪OIDC流。

让我们开始吧!

使用Spring Initializr和Okta创建一个OpenID Connect应用程序

您可以使用出色的Spring Initializr网站或API通过Okta集成创建示例OIDC应用程序:

curl https://start.spring.io/starter.zip \dependencies==web,okta \packageName==com.okta.developer.demo -d

但是,在运行OIDC应用程序之前,您将需要一个Okta帐户。 Okta是一项开发人员服务,可为您处理存储用户帐户和实施用户管理(包括OIDC)。 继续并注册一个免费的开发者帐户以继续。

登录到Okta帐户后,转到仪表板,然后转到“应用程序”部分。 添加一个新的Web应用程序,然后在“常规”部分中获取客户端凭据:客户端ID客户端密钥

您还将需要颁发者,它也是组织URL,您可以在仪表板主页的右上角找到它。 注意:默认情况下,内置的Everyone Okta组已分配给该应用程序,因此Okta组织中的任何用户都可以对其进行身份验证。

使用您的客户ID,客户密码。 然后在适当的位置发行者,通过在命令行中传递凭据来启动您的应用程序:

OKTA_OAUTH2_REDIRECTURI=/authorization-code/callback \
OKTA_OAUTH2_ISSUER=<issuer>/oauth2 \
OKTA_OAUTH2_CLIENT_ID=<client id> \
OKTA_OAUTH2_CLIENT_SECRET=<client secret> \
./mvnw spring-boot:run

将测试控制器添加到Spring Boot App

最好添加一个简单的控制器来测试身份验证流程。 默认情况下,仅允许经过身份验证的用户访问。

@Controller
@RequestMapping(value = "/hello")
public class HelloController {@GetMapping(value = "/greeting")@ResponseBodypublic String getGreeting(Principal user) {return "Good morning " + user.getName();}
}

您可以通过重新启动应用程序并浏览到/ hello / greeting来进行测试。

添加Spring Boot Actuator依赖关系

通过将启动器Maven依赖项添加到pom.xml file来启用Spring Boot Actuator:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

要启用httptrace端点,请编辑src/main/resources/application.properties并添加以下行:

management.endpoints.web.exposure.include=info,health,httptrace

您可以运行浏览到/ hello / greeting并登录的应用程序来测试现成的执行器功能。

在自动配置下,Spring Security过滤器的优先级高于httptrace执行器添加的过滤器。

这意味着默认情况下仅跟踪经过身份验证的呼叫。 我们将在此处对此进行更改,但是现在,您可以在/ actuator / httptrace中看到跟踪的内容。 响应应类似于以下JSON负载:

{"traces":[{"timestamp":"2019-05-19T05:38:42.726Z","principal":{"name":"***"},"session":{"id":"***"},"request":{"method":"GET","uri":"http://localhost:8080/","headers":{},"remoteAddress":"0:0:0:0:0:0:0:1"},"response":{"status":200,"headers":{}},"timeTaken":145}]
}

将自定义HTTP跟踪添加到您的Spring Boot App

HTTP跟踪不是很灵活。 httptrace执行器的作者Andy Wilkinson建议,如果需要进行身体跟踪,请实现自己的端点。

或者,通过一些自定义过滤器,我们无需进行大量工作即可增强基本实现。 在以下各节中,我将向您展示如何:

  • 创建一个过滤器以捕获请求和响应正文
  • 配置过滤器优先级以跟踪OIDC调用
  • 使用自定义跟踪存储库创建httptrace端点扩展,以存储其他数据

使用Spring Boot Actuator捕获请求和响应正文内容

接下来,创建一个用于跟踪请求和响应正文内容的过滤器。 此过滤器将优先于httptrace过滤器,因此当执行器保存跟踪时,缓存的正文内容可用。

@Component
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
public class ContentTraceFilter extends OncePerRequestFilter {private ContentTraceManager traceManager;@Value("${management.trace.http.tracebody:false}")private boolean traceBody;public ContentTraceFilter(ContentTraceManager traceManager) {super();this.traceManager = traceManager;}@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {if (!isRequestValid(request) || !traceBody) {filterChain.doFilter(request, response);return;}ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request, 1000);ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);try {filterChain.doFilter(wrappedRequest, wrappedResponse);traceManager.updateBody(wrappedRequest, wrappedResponse);} finally {wrappedResponse.copyBodyToResponse();}}private boolean isRequestValid(HttpServletRequest request) {try {new URI(request.getRequestURL().toString());return true;} catch (URISyntaxException ex) {return false;}}}

注意对ContentTraceManager的调用,它是一个简单的@RequestScope bean,它将存储其他数据:

@Component
@RequestScope
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
public class ContentTraceManager {private ContentTrace trace;public ContentTraceManager(ContentTrace trace) {this.trace=trace;}protected static Logger logger = LoggerFactory.getLogger(ContentTraceManager.class);public void updateBody(ContentCachingRequestWrapper wrappedRequest,ContentCachingResponseWrapper wrappedResponse) {String requestBody = getRequestBody(wrappedRequest);getTrace().setRequestBody(requestBody);String responseBody = getResponseBody(wrappedResponse);getTrace().setResponseBody(responseBody);}protected String getRequestBody(ContentCachingRequestWrapper wrappedRequest) {try {if (wrappedRequest.getContentLength() <= 0) {return null;}return new String(wrappedRequest.getContentAsByteArray(), 0,wrappedRequest.getContentLength(),wrappedRequest.getCharacterEncoding());} catch (UnsupportedEncodingException e) {logger.error("Could not read cached request body: " + e.getMessage());return null;}}protected String getResponseBody(ContentCachingResponseWrapper wrappedResponse) {try {if (wrappedResponse.getContentSize() <= 0) {return null;}return new String(wrappedResponse.getContentAsByteArray(), 0,wrappedResponse.getContentSize(),wrappedResponse.getCharacterEncoding());} catch (UnsupportedEncodingException e) {logger.error("Could not read cached response body: " + e.getMessage());return null;}}public ContentTrace getTrace() {if (trace == null) {trace = new ContentTrace();}return trace;}
}

为了使用附加数据对跟踪建模,请使用内置的HttpTrace信息组成一个自定义ContentTrace类,并添加用于存储正文内容的属性。

public class ContentTrace {protected HttpTrace httpTrace;protected String requestBody;protected String responseBody;protected Authentication principal;public ContentTrace() {}public void setHttpTrace(HttpTrace httpTrace) {this.httpTrace = httpTrace;}
}

httpTraceprincipalrequestBodyresponseBody添加设置器和获取httpTrace

配置过滤器优先级

为了捕获对您应用程序中OIDC端点的请求,跟踪过滤器必须位于Spring Security过滤器之前。 只要ContentTraceFilter优先级高于HttpTraceFilter ,那么两者都可以放在SecurityContextPersistenceFilter之前或之后,后者是Spring Security过滤器链中的第一个。

@Configuration
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {private HttpTraceFilter httpTraceFilter;private ContentTraceFilter contentTraceFilter;public WebSecurityConfig(HttpTraceFilter httpTraceFilter, ContentTraceFilter contentTraceFilter) {this.httpTraceFilter = httpTraceFilter;this.contentTraceFilter = contentTraceFilter;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.addFilterBefore(contentTraceFilter,SecurityContextPersistenceFilter.class).addFilterAfter(httpTraceFilter,SecurityContextPersistenceFilter.class).authorizeRequests().anyRequest().authenticated().and().oauth2Client().and().oauth2Login();}
}

跟踪经过身份验证的用户

我们将在Spring Security过滤器链之前安装跟踪过滤器。 这意味着当HttpTraceFilter保存跟踪时,主体不再可用。 我们可以使用新的过滤器和ContentTraceManager还原此跟踪数据。

@Component
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
public class PrincipalTraceFilter extends OncePerRequestFilter {private ContentTraceManager traceManager;private HttpTraceProperties traceProperties;public PrincipalTraceFilter(ContentTraceManager traceManager,HttpTraceProperties traceProperties) {super();this.traceManager = traceManager;this.traceProperties = traceProperties;}@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain)throws ServletException, IOException {if (!isRequestValid(request)) {filterChain.doFilter(request, response);return;}try {filterChain.doFilter(request, response);} finally {if (traceProperties.getInclude().contains(Include.PRINCIPAL)) {traceManager.updatePrincipal();}}}private boolean isRequestValid(HttpServletRequest request) {try {new URI(request.getRequestURL().toString());return true;} catch (URISyntaxException ex) {return false;}}}

添加缺少的ContentTraceManager类以更新主体:

public class ContentTraceManager {public void updatePrincipal() {Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication != null) {getTrace().setPrincipal(authentication);}}
}

PrincipalTraceFilter优先级必须低于Spring Security过滤器链的优先级,因此从安全上下文请求身份验证的主体时可用。 修改WebSecurityConfig以在安全链中的最后一个过滤器FilterSecurityInterceptor之后插入过滤器。

@Configuration
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {private HttpTraceFilter httpTraceFilter;private ContentTraceFilter contentTraceFilter;private PrincipalTraceFilter principalTraceFilter;public WebSecurityConfig(HttpTraceFilter httpTraceFilter,ContentTraceFilter contentTraceFilter,PrincipalTraceFilter principalTraceFilter) {super();this.httpTraceFilter = httpTraceFilter;this.contentTraceFilter = contentTraceFilter;this.principalTraceFilter = principalTraceFilter;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.addFilterBefore(contentTraceFilter,SecurityContextPersistenceFilter.class).addFilterAfter(httpTraceFilter,SecurityContextPersistenceFilter.class).addFilterAfter(principalTraceFilter,FilterSecurityInterceptor.class).authorizeRequests().anyRequest().authenticated().and().oauth2Client().and().oauth2Login();}
}

HTTPTrace端点扩展

最后,使用@EndpointWebExtension批注定义端点增强。 实现CustomHttpTraceRepository以存储和检索带有其他数据的ContentTrace

@Component
@EndpointWebExtension(endpoint = HttpTraceEndpoint.class)
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
public class HttpTraceEndpointExtension {private CustomHttpTraceRepository repository;public HttpTraceEndpointExtension(CustomHttpTraceRepository repository) {super();this.repository = repository;}@ReadOperationpublic ContentTraceDescriptor contents() {List<ContentTrace> traces = repository.findAllWithContent();return new ContentTraceDescriptor(traces);}
}

重新定义端点返回类型的描述符:

public class ContentTraceDescriptor {protected List<ContentTrace> traces;public ContentTraceDescriptor(List<ContentTrace> traces) {super();this.traces = traces;}public List<ContentTrace> getTraces() {return traces;}public void setTraces(List<ContentTrace> traces) {this.traces = traces;}}

创建CustomHttpTraceRepository实现HttpTraceRepository接口:

@Component
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
public class CustomHttpTraceRepository implements HttpTraceRepository {private final List<ContentTrace> contents = new LinkedList<>();private ContentTraceManager traceManager;public CustomHttpTraceRepository(ContentTraceManager traceManager) {super();this.traceManager = traceManager;}@Overridepublic void add(HttpTrace trace) {synchronized (this.contents) {ContentTrace contentTrace = traceManager.getTrace();contentTrace.setHttpTrace(trace);this.contents.add(0, contentTrace);}}@Overridepublic List<HttpTrace> findAll() {synchronized (this.contents) {return contents.stream().map(ContentTrace::getHttpTrace).collect(Collectors.toList());}}public List<ContentTrace> findAllWithContent() {synchronized (this.contents) {return Collections.unmodifiableList(new ArrayList<>(this.contents));}}}

检查OpenID Connect HTTP跟踪

通过添加以下行来修改application.properties文件以跟踪所有可用数据:

management.trace.http.include=request-headers,response-headers,cookie-headers,principal,time-taken,authorization-header,remote-address,session-id

再次运行该应用程序,然后调用安全控制器/ hello / greeting 。 针对Okta进行身份验证,然后检查/ actuator / httptrace中的跟踪。

现在,您应该在跟踪中看到OIDC调用以及请求和响应内容。 例如,在下面的跟踪中,对应用程序授权端点的请求将重定向到Okta授权服务器,从而启动OIDC授权代码流。

{"httpTrace": {"timestamp": "2019-05-22T00:52:22.383Z","principal": null,"session": {"id": "C2174F5E5F85B313B2284639EE4016E7"},"request": {"method": "GET","uri": "http://localhost:8080/oauth2/authorization/okta","headers": {"cookie": ["JSESSIONID=C2174F5E5F85B313B2284639EE4016E7"],"accept-language": ["en-US,en;q=0.9"],"upgrade-insecure-requests": ["1"],"host": ["localhost:8080"],"connection": ["keep-alive"],"accept-encoding": ["gzip, deflate, br"],"accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"],"user-agent": ["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"]},"remoteAddress": "0:0:0:0:0:0:0:1"},"response": {"status": 302,"headers": {"X-Frame-Options": ["DENY"],"Cache-Control": ["no-cache, no-store, max-age=0, must-revalidate"],"X-Content-Type-Options": ["nosniff"],"Expires": ["0"],"Pragma": ["no-cache"],"X-XSS-Protection": ["1; mode=block"],"Location": ["https://dev-239352.okta.com/oauth2/default/v1/authorize?response_type=code&client_id=0oalrp4qx3Do43VyI356&scope=openid%20profile%20email&state=1uzHRyaHVmyKcpb7eAvJVrdJTZ6wTgkPv3fsC14qdOk%3D&redirect_uri=http://localhost:8080/authorization-code/callback"]}},"timeTaken": 9},"requestBody": null,"responseBody": null
}

这篇文章中的所有代码都可以在okta-spring-boot-custom-actuator-example存储库的GitHub上找到。

学到更多

这里的所有都是它的! 您刚刚了解了如何配置和扩展httptrace执行器端点以监视OIDC应用程序。 有关Spring Boot Actuator,一般Spring Boot或用户身份验证的更多信息,请查看以下链接:

  • 带有Spring Boot和Spring Cloud的Java微服务
  • 弹簧启动执行器端点
  • 实施自定义端点
  • Okta身份验证快速入门指南Java Spring

与往常一样,如果您对此信息有任何意见或疑问,请在下面发表评论。 将来不要错过Twitter和YouTube上的任何精彩内容。

“使用Spring Boot Actuator监视Java应用程序”最初于2019年7月17日发布在Okta Developer博客上。

朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 数分钟之内即可在任何应用程序中对用户进行身份验证,管理和保护。

翻译自: https://www.javacodegeeks.com/2019/09/monitor-your-java-apps-spring-boot-actuator.html

actuator的原理

actuator的原理_使用Spring Boot Actuator监视Java应用程序相关推荐

  1. springboot有什么好的方案实现 数据实时更新吗?_使用Spring Boot Actuator、Jolokia和Grafana实现准实时监控...

    Spring Boot Actuator通过/metrics端点,以开箱即用的方式为应用程序的性能指标与响应统计提供了一个非常友好的监控方式. 由于在集群化的弹性环境中,应用程序的节点可以增长.扩展, ...

  2. java局部网内通话杂音_在Spring Boot反应式Web应用程序上启用SSL,并在控制台中对该打印进行http调用时出现异常噪音...

    在我创建了我的spring boot反应式Web应用程序以支持SSL之后,当我尝试对服务器进行http调用时,它会在控制台中的异常跟踪下面打印 . 作为应用程序所有者,我无法阻止任何人使用我的服务 . ...

  3. spring boot actuator工作原理之http服务暴露源码分析

    spring boot actuator的官方文档地址:https://docs.spring.io/spring-boot/docs/current/reference/html/productio ...

  4. Spring Boot Actuator与Spring Boot Admin详解

    原版文档: 文档:Spring Boot Actuator.note 链接:http://note.youdao.com/noteshare?id=fca965ad3f7ae3f79260d09056 ...

  5. Spring boot——Actuator 详解

    一.什么是 Actuator Spring Boot Actuator 模块提供了生产级别的功能,比如健康检查,审计,指标收集,HTTP 跟踪等,帮助我们监控和管理Spring Boot 应用. 这个 ...

  6. spring boot Actuator之自定义Endpoint

    本文基于spring boot 2.2.0 release版本. 在上一篇文章<spring boot Actuator原理详解之启动>详细介绍了在web环境下,Actuator是如何启动 ...

  7. 警惕 Spring Boot Actuator 引发的安全问题

    前言 一年一度的 HW 行动开始了,最近也是被各种安全漏洞搞的特别闹心,一周能收到几十封安全团队扫描出来的漏洞邮件,这其中有一类漏洞很容易被人忽视,但影响面却极广,危害也极大,我说出它的名字你应该也不 ...

  8. 朱晔和你聊Spring系列S1E7:简单好用的Spring Boot Actuator

    本文会来看一下Spring Boot Actuator提供给我们的监控端点Endpoint.健康检查Health和打点指标Metrics等所谓的Production-ready(生产环境必要的一些)功 ...

  9. 如何将 Spring Boot Actuator 的指标信息输出到 InfluxDB 和 Prometheus

    来源:SpringForAll社区 Spring Boot Actuator是Spring Boot 2发布后修改最多的项目之一.它经过了主要的改进,旨在简化定制,并包括一些新功能,如支持其他Web技 ...

最新文章

  1. R语言ggplot2可视化绘制线图(line plot)、使用gghighlight包突出高亮线图的满足条件的线图、设置高亮线图不显示默认自动显示的文本标签(use_direct_label)
  2. hibernate的Configuration类和SessionFactory接口
  3. Mac下SourceTree导出更新文件
  4. JQuery 定期刷新网页,保持登录状态Session
  5. 从Encoder到Decoder实现Seq2Seq模型
  6. hadoop eclipse plugin windows下载集合
  7. Linux crontab 定时任务没执行,没收到错误信息邮件
  8. Opencv 图片缩小尺寸原理
  9. where、having、group by、order by、limit的区别和使用顺序
  10. [Linux] DSO missing from command line
  11. Bailian2723 不吉利日期(POJ NOI0113-02)【日期计算】
  12. 麦克纳姆轮运动原理怎么安装_家用中央空调水系统原理是什么?怎么样安装比较好呢?...
  13. 关于suitescript 无法读取Item Number Field
  14. Plastic SCM2022版开源项目
  15. 教你用Python爬图虫网图片
  16. 读书笔记-人月神话8
  17. android支持的播放格式,android全格式多媒体播放器(一:ffmpeg移植)
  18. 计算机配置内存容量怎么调,如何设置电脑虚拟内存,电脑虚拟内存设置多少最合理?...
  19. python多线程爬取m3u8视频(包含AES解密)
  20. linux安装nginx防火墙,Centos7 防火墙关闭与nginx无法访问

热门文章

  1. 科学家揭示灵长类早期胚胎发育多能性的变化模式
  2. Spring Boot开始
  3. unix环境高级编程-线程(2)
  4. Silverlight 控件开发记录之 extern alias” 关键字
  5. 宽字符集(unicode)说明以及转换函数
  6. Linux RCU机制详解[转]
  7. Visual Studio 2005 Professional Released
  8. python3 multiprocessing 多进程 列表类型 listproxy 清除内容
  9. premiere pr 某个面板悬浮后怎么还原
  10. linux 创建临时文件目录 mktemp 命令 简介