<微服务安全架构与实践>学习笔记

本文探讨了微服务环境下安全架构的关键问题,包括开放系统间的授权管理、OAuth2的定义、流程及选型,重点讲解了OAuth2.0的授权码、简化模式、密码模式和客户端模式,并提供了Spring Security OAuth2的实现示例。此外,文章还介绍了JWT在微服务中的应用和下一代安全架构方案的选择。
摘要由CSDN通过智能技术生成

微服务安全要解决什么问题

1.开放系统间授权

在这里插入图片描述
不适用于开放系统间

在这里插入图片描述
developer key 可能泄露
在这里插入图片描述
与OAuth2比较接近, 需要考虑如何管理, 颁发令牌

2.现代微服务安全

在这里插入图片描述

在这里插入图片描述

  1. 服务粒度很小, 服务和服务之间怎么去认证和鉴权
  2. 应用的形态多种多样, 不只是浏览器, 还有单页应用, 原生APP, 服务器端APP

独立的服务AuthServer, 并且把认证和授权都做成一个Service … 基于Token的授权

3.总结

在这里插入图片描述

OAuth2的定义和原理

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

令牌: AccessToken : 由授权服务器颁发

在这里插入图片描述

在这里插入图片描述

OAuth2的正式定义

令牌 类比 仆从钥匙(Valet Key)

给应用授权有限的访问权限, 让应用能够代表用户去访问用户的数据

OAuth 2.0 优势

在这里插入图片描述

不足

在这里插入图片描述

主要角色

在这里插入图片描述
在这里插入图片描述

OAuth2 术语

在这里插入图片描述

令牌类型

在这里插入图片描述

误解

在这里插入图片描述

总结

在这里插入图片描述

OAuth2 的流程和选型

典型的OAuth Flow

1. 授权码模式

在这里插入图片描述

2. 简化模式

在这里插入图片描述

3. 密码模式

在这里插入图片描述
用户名和密码尽量不要泄露?
Client 不是第三方的, 是自己的, 风险不是特别大

4. 客户端模式

在这里插入图片描述

刷新令牌流程

在这里插入图片描述

OAuth Flow 选型

授权流程渠道

在这里插入图片描述
没有资源服务器参与的: 前端渠道

没有资源拥有者参与的: 后端渠道

客户应用类型

在这里插入图片描述

公开应用: 客户可以直接接触这些应用, 公开的, 不能存储重要的客户凭证信息 (客户密码), 可能会泄露
私密应用: client 在后端, 可以存储客户的凭证 (密码信息)

四种OAuth2授权类型(Flows)

在这里插入图片描述

授权类型选型参考

在这里插入图片描述

OAuth2 授权服务器和资源服务器案例实操

授权服务器的组成

在这里插入图片描述

Spring Security OAuth2 架构图

在这里插入图片描述

code1. 授权码模式授权服务器

code

引入依赖
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- for OAuth 2.0 -->
		<dependency>
			<groupId>org.springframework.security.oauth</groupId>
			<artifactId>spring-security-oauth2</artifactId>
		</dependency>
目录结构

在这里插入图片描述

资源api
@Controller
public class UserController {

	// 资源API
    @RequestMapping("/api/userinfo")
    public ResponseEntity<UserInfo> getUserInfo() {
        // 获取用户信息
        User user = (User) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();
        String email = user.getUsername() + "@spring2go.com";

        UserInfo userInfo = new UserInfo();
        userInfo.setName(user.getUsername());
        userInfo.setEmail(email);

        return ResponseEntity.ok(userInfo);
    }

}
授权服务器配置
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // inMemory 授权服务器的相关信息存在内存中, 不适用生产级
        clients.inMemory()
            // clientapp 客户名称, 112233 客户密码 -> 客户凭证, 一般通过授权服务器注册, 此demo简化
            .withClient("clientapp")
            .secret("112233")
            // 重定向url, 拿到授权码后跳转回客户端
            .redirectUris("http://localhost:9001/callback")
            // 指定授权码模式
            .authorizedGrantTypes("authorization_code")
            // 细分权限
            .scopes("read_userinfo", "read_contacts");
    }

}
资源服务器配置
@Configuration
// 启动资源服务器
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .requestMatchers()
            // 对哪些资源 (api端点) 下面的调用 进行 OAuth2的认证
            // UserController的资源必须带着token过来, 如果不带token or token失效 就会被拒绝
            .antMatchers("/api/**");
    }

}

lab

1. 发送请求获取授权码
http://localhost:8080/oauth/authorize?
client_id=clientapp
&redirect_uri=http://localhost:9001/callback // 重定向的URI
&response_type=code // 表示通过授权码的方式走流程 
&scope=read_userinfo // 只读userinfo 

跳转到该url
http://localhost:9001/callback?code=4bupW0 // 拿到授权码
2. 获取访问令牌

使用 postman 模拟 post请求 到 授权码端点

http://localhost:8080/oauth/token

http://localhost:8080/oauth/token?
code=y8h8sP // 第一步拿到的授权码
&grant_type=authorization_code
&redirect_uri=http://localhost:9001/callback
&scope =read_userinfo

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3. 访问资源

在这里插入图片描述

code2. 简化模式授权服务器

code

除了授权服务器配置, 其余都相同

授权服务器配置
@Configuration
@EnableAuthorizationServer
public class  OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(ClientDetailsServiceConfigurer clients)
            throws Exception {
        clients.inMemory()
            .withClient("clientapp")
            .secret("112233")
            .redirectUris("http://localhost:9001/callback")
            // 简化模式
            .authorizedGrantTypes("implicit")
            // 访问令牌的有效期, 120 seconds
            .accessTokenValiditySeconds(120)
            .scopes("read_userinfo", "read_contacts");
    }
}

lab

1.获取访问令牌
http://localhost:8080/oauth/authorize?
client_id=clientapp
&redirect_uri=http://localhost:9001/callback
&response_type=token // 与授权码模式(code)不同
&scope=read_userinfo
&state=abc // 可选, 安全起见生产环境启用

返回
http://localhost:9001/callback#
access_token=c15889f3-5a3f-4346-ac42-1afe77ec5414 // 在url中返回了token
&token_type=bearer
&state=abc
&expires_in=119
2.调用API访问资源

在这里插入图片描述

code3. 密码模式授权服务器

code

除了授权服务器配置, 其余都相同

// 授权服务器配置
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

	// 用户认证, 配置在授权服务器端点上 AuthorizationServerEndpoints
    // 因为用户名-密码模式, 直接把用户名密码传递给授权服务器, 
    // 授权服务器拿到用户名密码需要通过 SpringSecurity 的 AuthenticationManager 进行认证
    @Autowired
    private AuthenticationManager authenticationManager;

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // inMemory模式, 授权服务器的相关信息存在内存中
        clients.inMemory()
            // 用户名, 密码 -> 用户凭证
            .withClient("clientapp")
            .secret("112233")
            // 密码模式
            .authorizedGrantTypes("password")
            // 细分权限
            .scopes("read_userinfo", "read_contacts");
    }
}

lab

1. 获取访问令牌

使用 postman 模拟 post 请求
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2. 请求资源服务器

在这里插入图片描述

code4. 客户端模式授权服务器

code

资源api作修改

@Controller
public class UserController {
	// 资源API
    @RequestMapping("/api/userinfo")
    public ResponseEntity<UserInfo> getUserInfo() {
        // 获取用户信息
        User user = (User) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();
        String email = user.getUsername() + "@spring2go.com";

        UserInfo userInfo = new UserInfo();
        userInfo.setName(user.getUsername());
        userInfo.setEmail(email);

        return ResponseEntity.ok(userInfo);
    }
}

授权服务器

// 授权服务器配置
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
            .withClient("clientdevops")
            .secret("789")
            // 客户端模式
            .authorizedGrantTypes("client_credentials")
            // 细分权限
            .scopes("devops");
    }

} 

lab

1. 获取访问令牌

在这里插入图片描述

2. 访问资源

在这里插入图片描述

JWT令牌

类型分类

在这里插入图片描述

JWT是一种 自包含令牌
在这里插入图片描述
自解释的token 需要有签名 signature
类似支票
在这里插入图片描述

在这里插入图片描述
对应audience,
JWT 自解释, 自校验特性

code

配置授权服务器
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    /**
     * 用户名密码模式需要启用 spring security 的 AuthenticationManager
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * 对JWT进行签名的话需要增加一个秘钥, 在授权服务器也要通过这个秘钥来解签
     *
     * @return
     */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("test-secret");
        return converter;
    }

    /**
     * 生成的token是由JwtTokenStore生成的
     * @return
     */
    @Bean
    public JwtTokenStore jwtTokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    /**
     * 配置授权端点, 支持生成JWT的token, 签名需要用到 accessTokenConverter
     *
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .authenticationManager(authenticationManager)
            .tokenStore(jwtTokenStore())
            .accessTokenConverter(accessTokenConverter());
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
            // 设置客户凭证
            .withClient("clientapp")
            .secret("112233")
            .scopes("read_userinfo")
            // 授权服务器可以同时支持三种模式
            .authorizedGrantTypes(
                "password",
                "authorization_code",
                "refresh_token");
    }
}
配置资源服务器

在这里插入图片描述

@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends
    ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated().and()
            // 对api的访问端点都需要进行校验
            .requestMatchers().antMatchers("/api/**");
    }
}

在application.properties里设置校验的私钥key

server.port=8081

#springboot 自动的去加载相应的jwt处理的代码
#如果请求的是jwt的token, 用该配置去作为解签签名去校验令牌 是否是正确令牌
security.oauth2.resource.jwt.key-value=test-secret

lab

1.获取JWT令牌

在这里插入图片描述
在这里插入图片描述
使用 postman 模拟 POST 请求
在这里插入图片描述
获得令牌
在这里插入图片描述

2.请求资源服务器

在这里插入图片描述

OpenID Connect 简介

OAuth2 – 授权协议

在这里插入图片描述

在OAuth2上增加了一个身份认证层

下一代微服务安全架构

方案一

在这里插入图片描述
③ 做一个access token 和 JWT token 的一个交换
因为 access token 是透明的, 无意义的
而且不想让后面的微服务分别校验, 让网关集中校验

每个微服务可以根据自己的情况增加OAuthFilter
因为JWT token是自校验的, 是无状态的校验方式, 不需要到授权服务器去集中校验
可以通过OAuthFilter去校验JWT token并获取相应的用户信息

方案二

在这里插入图片描述

授权服务器和API网关之间有一个秘钥

好处: 网关不需要到授权服务器上去集中校验, 可以本地自校验
坏处: 缺少了集中校验环节, 没有集中的吊销点, 只能等JWT自动过期
没办法一次性把用户剔除, 建议JWT自动过期时间设置得短一点

方案三

在这里插入图片描述
网关做 access token 和 JWT 转换时使用 redis 缓存, 第一种方案的优化

监控指标

在这里插入图片描述
高可用的, 多台的, 水平扩容

开源产品

在这里插入图片描述

提供SaaS服务

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值