【发布时间】:2021-02-12 20:34:31
【问题描述】:
我正在学习如何使用基本身份验证和 OAuth2 JWT 令牌身份验证来保护微服务。我使用基本身份验证实现了它,现在我想在 OAuth2 身份验证中对其进行转换。
这是使用基本身份验证保护这两个微服务之间通信的实现。
微服务 1 - REST API
@Configuration
@Getter
public class DemoApiConfiguration {
@Value("${demo.api.credentials.username}")
private String username;
@Value("${demo.api.credentials.password}")
private String password;
}
SecurityConfigurer 类:
@Configuration
@RequiredArgsConstructor
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
private final DemoApiConfiguration apiConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails theUser = User.withUsername(apiConfig.getUsername())
.password(passwordEncoder.encode(apiConfig.getPassword())).roles("USER").build();
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
userDetailsManager.createUser(theUser);
return userDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
控制器类:
@RestController
@RequestMapping("/rest/api/v1")
public class HomeController {
@GetMapping("/products")
public String home() {
return "These are products!";
}
}
application.yml:
demo:
api:
credentials:
username: ${demo_api_username:john}
password: ${demo_api_password:test}
微服务 2 - REST 消费者
@Configuration
@Getter
public class DemoApiConfiguration {
@Value("${demo.api.credentials.username}")
private String username;
@Value("${demo.api.credentials.password}")
private String password;
@Value("${demo.api.credentials.basePath}")
private String basePath;
}
WebConfigurer 类:
@Configuration
@RequiredArgsConstructor
public class WebConfigurer {
private final DemoApiConfiguration apiConfig;
@Bean
public ApiClient restTemplate() {
RestTemplate restTemplate = new RestTemplate();
ApiClient apiClient = new ApiClient(restTemplate);
apiClient.setBasePath(apiConfig.getBasePath());
return apiClient;
}
public String getAuthorization() {
return (!StringUtils.isEmpty(apiConfig.getUsername()) &&
!StringUtils.isEmpty(apiConfig.getPassword())) ?
"Basic " + Base64Utils.encodeToString((
apiConfig.getUsername() + ":" + apiConfig.getPassword())
.getBytes()) :
null;
}
}
ApiClient 类:
@Getter
@RequiredArgsConstructor
@Slf4j
public class ApiClient {
private static final String AUTHORIZATION_HEADER = "Authorization";
private final RestTemplate restTemplate;
private String basePath;
public ApiClient setBasePath(String basePath) {
this.basePath = basePath;
return this;
}
public String invokeApi(String path, String credentials) {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(basePath).path(path);
RequestEntity.BodyBuilder requestBuilder =
RequestEntity.method(HttpMethod.GET, builder.build().toUri());
requestBuilder.contentType(MediaType.APPLICATION_JSON);
requestBuilder.header(AUTHORIZATION_HEADER, credentials);
RequestEntity<Object> requestEntity = requestBuilder.body(null);
return restTemplate
.exchange(requestEntity, String.class).getBody();
}
}
ConsumeController 类:
@RestController
@RequiredArgsConstructor
public class ConsumeController {
private static final String PATH = "/rest/api/v1/products";
private final WebConfigurer webConfigurer;
private final ApiClient apiClient;
@GetMapping(value = "/products-client")
public String getProductList() {
return apiClient.invokeApi(PATH, webConfigurer.getAuthorization());
}
}
application.yml:
server:
port: 8090
demo:
api:
credentials:
username: ${demo_api_username:john}
password: ${demo_api_password:test}
basePath: ${demo_api_path:http://localhost:8080}
所以第一个微服务是一个 REST API,第二个微服务是一个 REST 消费者,并且使用基本身份验证来保护通信。
现在我想使用 OAuth2 实现,我想问您如何使用 OAuth2 保护通信?所以我想添加另一个端点,比如“/access-token”,客户端首先会在这个端点上使用用户名和密码进行请求,并获得一个 jwt 令牌。之后,将使用此 jwt 令牌请求带有 Authorization 标头的“/products”端点。你能帮我做这种实施吗?谢谢!
【问题讨论】:
-
能否请您查看现有答案并提供反馈?谢谢!
-
嗨,svr,我刚刚查看了答案,一切都很好,而且您的答案也很棒,因为它是关于 OAuth 实施的。我没有时间实现它,因为我工作很忙,我想在周末实现它。谢谢!
标签: java spring-boot spring-security oauth-2.0 jwt