当前位置: 首页 > 知识库问答 >
问题:

Spring-远程基本身份验证

微生烨然
2023-03-14

我正在将Monolith Java/Spring服务器重写为MicroService,同时向客户机公开相同的API接口,这样他们就不会注意到任何更改。

在Monolith服务器中,我们使用Spring-SecuritySpring-Security-OAuth2

第一部分是创建一个基于Java的API-Gateway,它将处理所有身份验证/授权作为通往Monolith服务器的隧道。

创建新的微服务(使用spring Initializer)后,我尝试将spring security配置为使用以下方式将所有身份验证隧道到Monolith服务器:

@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安全的http://localhost:8080/login页面时,我可以成功登录,请求被隧道到我们的Monolith服务器。

当我尝试配置OAuth2资源服务器时,问题就出现了,因为我们的客户端当前正在使用POST-tooauth/token进行身份验证,头中有一些基本身份验证:

Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

注意:基本的令牌是所有客户端的静态令牌(我知道它没有任何价值,但这是它目前的实现方式,我试图实现一个完全兼容的API-Gateway)

这允许他们与该endpoint通信,并获取正文中用户/密码的有效令牌(即application/x-www-form-urlencoded):

password=somepassword&username=user@example.com&grant_type=password&scope=read%20write

问题是Spring Security返回一个401未授权的调用,甚至不允许请求输入/oauth/log路由并进行远程身份验证。

我找不到将基本身份验证隧道到整体服务器的方法,所以/oauth/log实际上将通过远程基本身份验证对整体进行身份验证,成功后,它将充当隧道,并将主体本身传递到整体/oauth/log终端(正如我在上面的WebSecurityConfig中所做的那样)

任何指示都将不胜感激。提前谢谢!


共有1个答案

朱欣荣
2023-03-14

我正在做一个类似的项目,我想我可以帮你一些指导。

OAuth2是基于令牌的安全授权和身份验证,我们可以分为四个组件:

  1. 受保护的资源(只能由具有适当授权的经过身份验证的用户访问)
  2. 资源所有者(定义什么应用程序可以调用他们的服务、允许哪些用户访问服务以及他们可以做什么)
  3. 应用程序(代表用户调用服务的应用程序)
  4. 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);
    }

}

我们创建一个将公开用户信息的endpoint。此endpoint将被其他服务调用。这就是为什么我们用@EnableResourceServer注释这个应用程序的原因。下面是返回用户信息的restendpoint:

@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-端口/oauth/token

授权类型:基本,用户名:客户端id,密码:客户端密码

正文:表单数据

Grant:密码

范围:网络客户端

用户名:您的用户名

密码:您的密码

在检索令牌之后,测试您是否可以访问该令牌以及您公开用户信息的endpoint的URL。

HttpMethod:Get,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>

下一步是应用程序。我们配置您的oauth2服务的服务点。之所以这样做,是因为monolith是一个受保护的服务,每次请求到来时,您都希望检查请求的令牌是否有效。

security:
 oauth2:
  resource:
   userInfoUri: http://localhost:oauth2-app-port/auth/user

在这之后,别忘了添加@EnableResourceServer,它使monolith成为受保护的资源。


@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服务进行身份验证,并拥有生成的令牌。使用生成的令牌通过网关服务器向monolith发送请求。网关试图通过传播从请求中接收的令牌来访问整体。整体检查令牌是否有效。

下面是我的微服务架构与zuul网关服务器和oauth2服务器的链接:https://github.com/rshtishi/payroll.如果您想查看更多详细信息,可以查看它。

 类似资料:
  • 我正在尝试使用OAuth2实现开发一个带有Spring Security性的rest api。但是如何删除基本身份验证呢。我只想向body发送用户名和密码,并在postman上获取令牌。 要删除基本身份验证,并从邮递员的get token中发送body标记中的用户名密码吗 我遇到了一些问题{"错误":"未经授权","error_description":"没有客户端身份验证。尝试添加适当的身份验证

  • 但我对spring-boot/java还是个新手...有谁能帮我把这条路走对吗? 多谢了。

  • 问题是当我尝试验证: 正文: 我总是有一个401错误状态,因为我的自定义入口点。在我看来,spring security并没有调用Authentication-Manager。我错过什么了吗?

  • 我一直在努力遵循这个教程: https://www.baeldung.com/spring-security-basic-authentication 我创建了几个restendpoint,如下所示: 现在的问题是,每当我试图发送POST请求时,我都会得到以下错误消息: HTTP状态401-访问此资源需要完全身份验证 我尝试了两种方法来发送请求,一种是通过邮递员 1.1 401 set-cooki

  • 问题内容: 从HttpClient 4.3开始,我一直在使用HttpClientBuilder。我正在连接到具有基本身份验证的REST服务。我将凭据设置如下: 但是,这不起作用(我正在使用的REST服务返回401)。怎么了? 问题答案: 从此处的 抢先身份验证 文档中: http://hc.apache.org/httpcomponents-client- ga/tutorial/html/aut

  • http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.3.xsd“>