我正在将Monolith Java / Spring服务器重写为微服务,同时向客户端公开相同的API接口,这样他们就不会注意到所做的任何更改。
在Monolith服务器中,我们使用Spring-Security
和Spring-Security-OAuth2
。
第一部分是创建一个基于Java的API网关,它将处理所有身份验证/授权,作为通往Monolith服务器的隧道。
使用Spring Initializr创建新的微服务后,我尝试使用以下方法配置Spring安全性以将所有身份验证隧道传输到Monolith Server:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthenticationProvider authenticationProvider;
public WebSecurityConfig(AuthenticationProvider authenticationProvider) {
this.authenticationProvider = authenticationProvider;
}
}
@Component("authenticationProvider")
public class CustomRemoteAuthenticationProvider extends RemoteAuthenticationProvider {
@Override
@Autowired
@Qualifier("remoteAuthenticationManager")
public void setRemoteAuthenticationManager(RemoteAuthenticationManager remoteAuthenticationManager) {
super.setRemoteAuthenticationManager(remoteAuthenticationManager);
}
}
@Service("remoteAuthenticationManager")
public class CustomRemoteAuthenticationManager implements RemoteAuthenticationManager {
@Override
public Collection<? extends GrantedAuthority> attemptAuthentication(String username, String password) throws RemoteAuthenticationException {
... here I do an HTTP call to the Monolith `/oauth/login`
}
}
当我访问spring-security的http://localhost:8080/login
页面时,这似乎正在工作,我可以成功登录并将请求传输到我们的Monolith服务器中。
当我尝试配置OAuth2
资源服务器时,问题开始了,因为我们的客户端当前正在使用POST对oauth/token
进行身份验证,并且标题中包含一些基本身份验证:
Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
注意:基本令牌是所有客户端的静态令牌(我知道它不值钱,但是这是当前实现的方式,我尝试实现完全兼容的API网关)
这允许他们与该端点进行通信并获得体内用户/密码的有效令牌(这是application / x-www-form-urlencoded):
password=somepassword&username=user@example.com&grant_type=password&scope=read%20write
问题在于,spring-security为该调用返回了401 Unauthorized
,甚至没有让请求进入/oauth/login
路由并进行远程身份验证。
我找不到将基本身份验证隧道传输到Monolith服务器中的方法,因此/oauth/login
实际上会通过远程基本身份验证针对Monolith进行身份验证,成功后它将充当隧道并通过正文本身进入Monolith /oauth/login
端点(就像我在上面的WebSecurityConfig
中所做的那样)
任何方向将不胜感激。 预先感谢!
答案 0 :(得分:0)
我正在做一个类似的项目,我认为我可以为您提供一些指导。
OAuth2是基于令牌的安全授权和身份验证,我们可以将其分为四个部分:
在您的情况下,受保护的资源就是您要在微服务体系结构中打破的整体。
从spring intilizr创建SpringCloud项目,确保存在以下依赖项:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
在那之后,在oauth2服务的主类中,您需要添加两个注释。 @EnableResourceServer
用于告诉您的微服务这是一种受保护的资源。我将在下面解释为什么需要这样做。 @EnableAuthorizationServer
将告诉Spring Cloud服务将被用作OAuth2Service。下面是代码片段:
@SpringBootApplication
@EnableResourceServer
@EnableAuthorizationServer
public class Oauth2ServerApplication {
public static void main(String[] args) {
SpringApplication.run(Oauth2ServerApplication.class, args);
}
}
我们创建一个将公开用户信息的终结点。该端点将被其他服务调用。这就是为什么我们用@EnableResourceServer
对该应用程序进行注释的原因。以下是返回用户信息的其余端点:
@RestController
@RequestMapping("/user")
public class UserRestController {
@GetMapping(produces="application/json")
public Map<String,Object> getUser(OAuth2Authentication user){
Map<String,Object> userInfo = new HashMap<>();
userInfo.put("user",user.getUserAuthentication().getPrincipal());
userInfo.put("authorities", user.getUserAuthentication().getAuthorities());
return userInfo;
}
}
现在,您将在oauth2服务中注册该应用程序。您将定义将访问受保护资源的应用程序。您将创建一个配置类,该类将定义哪些应用程序可以使用您的服务。
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
OAuth2ConfigParameters oauth2ConfigParameters;
@Bean
public OAuth2ConfigParameters oAuth2ConfigParameters() {
return new OAuth2ConfigParameters();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("your application")
.secret("your password")
.authorizedGrantTypes( "refresh_token","password","client_credentials")
.scopes("webclient","mobileclient");
}
}
您需要定义应用程序的用户和角色。如果您已经使用SpringBoot完成了安全性,这是很熟悉的。检查以下代码段:
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
@Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("you user")
.password(passwordEncoder().encode("your password"))
.roles("your role");
}
}
最后与邮递员联系,以检查是否可以从oauth2服务中检索令牌。
HttpMethod :POST, URL :http://localhost:application-port/oauth/token
授权类型:基本,用户名:客户端ID,密码:客户端机密
正文:表单数据
grant:密码
scope:webclient
用户名:您的用户名
密码:您的密码
检索令牌后,测试是否可以访问公开用户信息的端点的URL。
HttpMethod :获取, URL :localhost:application-port / user
授权:不记名,令牌:生成的令牌
首先,您需要将Spring Security和OAuth2 jar添加到您要保护的服务中。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
接下来,在整体的application.yml中,我们配置您的oauth2服务的服务点。这样做是因为整体是受保护的服务,并且每次请求到来时,您都要检查请求的令牌是否有效。
security:
oauth2:
resource:
userInfoUri: http://localhost:oauth2-app-port/auth/user
在那之后,别忘了添加@EnableResourceServer
,它使整装成为受保护的资源。
@SpringBootApplication
@EnableResourceServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
此后,我们指定所需的限制。我在下面提供了示例,将访问权限限制为仅通过身份验证的用户。
@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
}
您的用户已通过OAuth服务进行了身份验证,并具有生成的令牌。使用生成的令牌,通过网关服务器将请求发送给整体。网关尝试通过传播从请求中收到的令牌来访问整体。整体检查令牌是否有效。
下面是我的微服务架构与zuul网关服务器和oauth2服务器的链接:https://github.com/rshtishi/payroll。 如果您想查看更多详细信息,可以进行检查。