保护微服务-OAuth2

114 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 13 天,点击查看活动详情

Hi~ o( ̄▽ ̄)ブ,我是Young,今天我又比昨天更博学了,你呢?

安全这个词是所有研发人员所避不开的话题,尤其是在如今微服务盛行的局面,如何保证微服务的安全更是变得尤为重要。那么如何实现微服务的权限验证和授权问题,就是我们接下来要聊的 Spring Cloud SecurityOAuth2(Open Authentication)的事了。

OAuth2 是一个基于令牌的安全框架,允许用户使用第三方服务来验证。用户成功验证后将会持有一个令牌,该令牌随着每次的请求一起发送。验证服务将负责对该令牌进行身份确认。OAuth2的设计初心是不需要用户在每个微服务的请求中都提供自己的凭证信息就能验证身份。SpringBoot和Spring Cloud都提供了对应的OAuth2的实现,方便快速集成开发。而OAuth2真正强大的地方在于,它允许开发人员方便快捷的与第三方云服务提供商集成。并使用这些服务进行身份验证和授权,而无需将用户的凭证传递给第三方服务。

OAuth2 简介

前面我们说过OAuth2是基于令牌的安全和授权框架。它将安全分为4个部分

  • 受保护资源:这是开发人员要保护的资源,需要验证用户身份才能访问。
  • 资源持有者:可以定义哪些应用程序可以调用自身服务,哪些用户可以访问自身,以及他们可以利用该服务完成哪些事情。
  • 应用程序:代表用户调用其他服务的程序
  • OAuth2验证服务器:验证用户凭证的服务器,可以看成是应用程序和其他程序的中间程序,帮助验证身份的。
image.png

OAuth2为开发人员提供了4种授权验证方案:

  • password:密码
  • client credential:客户端凭据
  • authorization code:授权码
  • implicit:隐式

开始保护

依赖引入

新建一个SpringBoot项目,作为OAuth2服务,pom文件引入:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-security</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>

编写启动类

@SpringBootApplication
@RestController
@EnableResourceServer
//用于告诉Spring Cloud,该服务将作为OAuth2服务
@EnableAuthorizationServer
public class AuthApplication {

    @RequestMapping("/user")
    public Map<String,Object> user(OAuth2Authentication user){
        Map<String,Object> userinfo = new HashMap<>();
        userinfo.put("user",user.getUserAuthentication().getPrincipal());
        userinfo.put("authorities", AuthorityUtils.authorityListToSet(user.getUserAuthentication().getAuthorities()));
        return userinfo;
    }
    
    public static void main(String[] args) {
        SpringApplication.run(AuthApplication.class, args);
    }

}

配置应用程序

完成上面的代码编写后我们就有了一个验证服务,但我们还未定义任何应用程序、用户或角色。我们需要创建一个配置类OAuth2Config来配置相关的客户端、用户、角色等相关数据。

@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("order")
                .secret("123456")
                .authorizedGrantTypes("refresh_token","password","client_credentials")
                .scopes("webclient","mobileclient");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }
}

OAuth2Config类继承了AuthorizationServerConfigurerAdapter类,使用@Configuration注解对这个类进行标记。AuthorizationServerConfigurerAdapter是Spring Security的核心部分,它提供了验证和授权的基本机制。我们这里覆写了它的configure()方法,定义通过验证服务注册了哪些客户端程序。ClientDetailsServiceConfigurer类支持两种不同类型的存储:内存和JDBC。我们这里我们以memory为例。

  • withClient提供了注册的应用程序的名称
  • secret定义了密钥
  • authorizedGrantTypes定义了支持的授权类型
  • scopes定义了调用应用程序在请求OAuth2服务器获取令牌后可以操作的范围。

配置用户、角色

我们已经定义了应用程序级的密钥,接下来我们要创建用户(及其角色),这里我们定义了2个用户并赋予不同的角色。

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected UserDetailsService userDetailsService() {
        return super.userDetailsService();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("james")
                .password("james123123")
                .roles("USER")
                .and()
                .withUser("bob")
                .password("bob123123")
                .roles("USER","ADMIN");
    }
}

验证用户

此时我们将服务启动起来,然后用Postman发送Post请求到 http://localhost:8080/auth/oauth/token 即可获取到access_token,然后带着token去访问我们的 http://localhost:8080/auth/user 接口就能看到用户信息。

image.png image.png