Spring-Boot Actuator:使用JWT访问敏感的管理端点

时间:2017-10-15 01:10:05

标签: spring jwt spring-boot-actuator

我主要关注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因为它接近我需要的内容,但我不一定需要浏览器而且该问题没有得到解答。

与教程相比,我将spring-boot-starter-actuator作为我的pom.xml中的依赖项。

我的 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

我的 AccountUserDetailsS​​ervice 如下所示:

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

它返回access_token以及JSON回复中的更多信息。

然而,如果我尝试访问敏感端点(例如/ manage / shutdown),请执行以下操作:

curl -X POST -H"Authorization: bearer b8412762-af80-4b7d-9eb9-3fa472dd37c9" localhost:9191/manage/shutdown

我收到以下错误消息:

  

{"时间戳":1508029184236,"状态":401,"错误":"未授权""消息&# 34;:"全   访问它需要身份验证   资源""路径":" /管理/关机"}

我错过了什么/做错了什么?如果令牌有效(给定适当的权限/角色),我怎样才能让spring-boot执行器识别JWT并执行给定的敏感端点?

1 个答案:

答案 0 :(得分:0)

根据您分享的信息,您实际上并没有告诉Spring使用您的自定义UserDetailsS​​ervice。为了做到这一点,你必须有一个扩展WebSecurityConfigurerAdapter的类,然后覆盖configure(AuthenticationManagerBuilder auth)方法,如下所示:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.userDetailsService(customUserDetailsService);
}

有关OAuth2和自定义UserDetailsS​​ervice的更多信息,请参阅此处:https://stackoverflow.com/a/43245998/1320627

确保正确配置用户详细信息服务的最简单方法是添加REST端点,使用身份验证进行保护,然后尝试点击它。