Spring-Boot Actuator:使用 JWT 访问敏感的管理端点
Posted
技术标签:
【中文标题】Spring-Boot Actuator:使用 JWT 访问敏感的管理端点【英文标题】:Spring-Boot Actuator: access sensitive management endpoints with JWT 【发布时间】:2018-03-26 19:43:36 【问题描述】:我主要关注https://www.youtube.com/watch?v=EoK5a99Bmjc&list=WL&index=12(总结:https://netcrash.wordpress.com/2017/08/21/summary-of-josh-long-youtube-video-about-security-oauth/#comment-39,直到 ResourceServer 发挥作用)。
我已阅读Access sensitive Spring boot actuator endpoints via tokens in browser,因为它接近我需要的内容,但我不一定需要浏览器,并且该问题没有得到解答。
与教程相比,我在 pom.xml 中包含 spring-boot-starter-actuator 作为依赖项。
我的 application.properties 如下所示:
logging.level=DEBUG
server.port=9191
endpoints.health.enabled=true
endpoints.health.sensitive=false
endpoints.shutdown.enabled=true
endpoints.shutdown.sensitive=true
management.contextPath: /manage
management.security.enabled=true
我的 AccountUserDetailsService 如下所示:
package com.divstar.particle.authservice.rest;
import java.text.MessageFormat;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class AccountUserDetailsService implements UserDetailsService
private final IAccountRepository accountRepository;
public AccountUserDetailsService(final IAccountRepository accountRepository)
this.accountRepository = accountRepository;
@Override
public UserDetails loadUserByUsername(final String username)
return accountRepository.findByUsername(username)
.map(account -> new User(account.getUsername(), account.getPassword(), account.isEnabled(),
account.isNonExpired(), account.isCredentialsNonExpired(), account.isNonLocked(),
AuthorityUtils.createAuthorityList("ROLE_ADMIN", "ROLE_USER", "ROLE_ACTUATOR")))
.orElseThrow(() -> new UsernameNotFoundException(
MessageFormat.format("Could not find the user 0!", username)));
我包含了角色“ROLE_ACTUATOR”,因为这似乎是执行器访问管理服务端点所需要的。
主应用程序类看起来相当简单:
package com.divstar.particle.authservice;
import java.util.stream.Stream;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.divstar.particle.authservice.rest.Account;
import com.divstar.particle.authservice.rest.IAccountRepository;
@SpringBootApplication
public class Application
@Bean
CommandLineRunner initUsers(final IAccountRepository userRepository)
return args -> Stream.of("test,long", "blame,short", "pass,secure")
.map(tpl -> tpl.split(","))
.forEach(tpl -> userRepository.save(new Account(tpl[0], tpl[1], "sample@mail.com", true, true, true, true)));
public static void main(final String[] args)
SpringApplication.run(Application.class, args);
IAccountRepository 扩展了 JpaRepository 并定义了“findByUsername”,它返回 Optional。
我的 AuthorizationServerConfigurationAdapter 看起来像这样:
package com.divstar.particle.authservice;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
@Configuration
@EnableAuthorizationServer
public class AuthServiceConfiguration extends AuthorizationServerConfigurerAdapter
private final AuthenticationManager authenticationManager;
public AuthServiceConfiguration(final AuthenticationManager authenticationManager)
super();
this.authenticationManager = authenticationManager;
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception
clients
.inMemory()
.withClient("html5")
.secret("clientsecret")
.authorizedGrantTypes("password")
.scopes("openid");
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.authenticationManager(authenticationManager);
启动身份验证服务器后,我使用以下 cURL 命令获取令牌:
curl html5:clientsecret@localhost:9191/oauth/token -d grant_type=password -d username=test -d password=long
它在 JSON 回复中返回 access_token 以及更多信息。
但是,如果我尝试像这样访问敏感端点(例如 /manage/shutdown):
curl -X POST -H"Authorization: bearer b8412762-af80-4b7d-9eb9-3fa472dd37c9" localhost:9191/manage/shutdown
我收到以下错误消息:
"timestamp":1508029184236,"status":401,"error":"Unauthorized","message":"Full 需要身份验证才能访问此 资源","路径":"/manage/shutdown"
我错过了什么/做错了什么?如果令牌有效(给定适当的权限/角色),我如何让 spring-boot 执行器识别 JWT 并执行给定的敏感端点?
【问题讨论】:
【参考方案1】:根据您共享的信息,您似乎并没有真正告诉 Spring 使用您的自定义 UserDetailsService。为此,您必须拥有一个扩展 WebSecurityConfigurerAdapter 的类,然后像这样覆盖 configure(AuthenticationManagerBuilder auth)
方法:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(customUserDetailsService);
有关 OAuth2 和自定义 UserDetailsService 的更多信息,请参见此处:https://***.com/a/43245998/1320627
确保正确配置用户详细信息服务的最简单方法是添加 REST 端点,通过身份验证进行保护,然后尝试点击它。
【讨论】:
我确实没有扩展 WebSecurityConfigurerAdapter 也没有在那里注入我的自定义 UserDetailsService。我现在尝试了这个,但它似乎没有改变任何东西。如果我有执行器端点的自定义安全性,我是否需要打开或关闭 "management.security.enabled"?我将使用新创建的课程更新我的问题。我也不完全理解您所说的“添加 REST 端点”是什么意思——我认为执行器已经这样做了?除了我不知道如何正确保护它。 有趣。我的意思是建议您添加一个新的控制器获取映射,以便您可以测试您的身份验证过程是否正常工作。你是对的,Actuator 做同样的事情。如果您有一个有效的现有控制器映射,那么您将获得更多信息来追踪问题。我怀疑问题仍然在于您的授权配置。稍后会更多。以上是关于Spring-Boot Actuator:使用 JWT 访问敏感的管理端点的主要内容,如果未能解决你的问题,请参考以下文章
spring-boot Actuator 连同 Spring Security 和 Form Basic Auth
关于spring-boot-actuator的httptrace端点不生效问题解决办法