【Oauth2整合gateway网关实现微服务单点登录】

文章目录

一.什么是单点登录?

单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。它的用途在于,不管多么复杂的应用群,只要在用户权限范围内,那么就可以做到用户只需要登录一次就可以访问权限范围内的所有应用子系统。

二.Oauth2整合网关实现微服务单点登录

网关整合 OAuth2.0 有两种思路:

  • 一种是授权服务器生成令牌, 所有请求统一在网关层验证,判断权限等操作;
  • 另一种是由各资源服务处理,网关只做请求转发。

比较常用的是第一种,把API网关作为OAuth2.0的资源服务器角色,实现接入客户端权限拦截、令牌解析并转发当前登录用户信息给微服务,这样下游微服务就不需要关心令牌格式解析以及OAuth2.0相关机制了。

网关在认证授权体系里主要负责两件事:

(1)作为OAuth2.0的资源服务器角色,实现接入方权限拦截。

(2)令牌解析并转发当前登录用户信息(明文token)给微服务

微服务拿到明文token(明文token中包含登录用户的身份和权限信息)后也需要做两件事:

(1)用户授权拦截(看当前用户是否有权访问该资源)

(2)将用户信息存储进当前线程上下文(有利于后续业务逻辑随时获取当前用户信息)

三.时序图

四.代码实现思路

1.基于OAuth2独立一个认证中心服务出来

  • 启动OAuth2认证授权中心:需要定义配置类重新AuthorizationServerConfigurerAdapter认证服务配置适配器类的3个configure方法。
    以及需要用到spring-security的WebSecurityConfigurerAdapter类等等,这里不贴代码了,只讲思路。
  • 比如我认证中心服务配置完,端口启动为:8888。

2.网关微服务

我们要自定义认证过滤器。认证过滤器里面需要做:

  1. 获取请求头里面的token信息
  2. 然后传入参数token信息通过rpc调用认证服务 http://auth-server/oauth/check_token进行token认证。
    也可以定义授权过滤器:进行token信息里面的自定义权限校验等等,需要使用@Order(1)注解,值越小优先级越高,指定这个过滤器在认证过滤器之后。
  3. 然后向下游业务系统传递解析后的token信息。

我启动端口为:8880,下面是认证过滤器核心代码:

java 复制代码
/**
 * 认证过滤器
 */
@Component
@Order(0)
public class AuthenticationFilter implements GlobalFilter, InitializingBean {

    @Autowired
    private RestTemplate restTemplate;

    private static Set<String> shouldSkipUrl = new LinkedHashSet<>();
    @Override
    public void afterPropertiesSet() throws Exception {
        // 不拦截认证的请求
        shouldSkipUrl.add("/oauth/token");
        shouldSkipUrl.add("/oauth/check_token");
        shouldSkipUrl.add("/user/getCurrentUser");
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String requestPath = exchange.getRequest().getURI().getPath();
        
        //不需要认证的url
        if(shouldSkip(requestPath)) {
            return chain.filter(exchange);
        }

        //获取请求头
        String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

        //请求头为空
        if(StringUtils.isEmpty(authHeader)) {
            throw new RuntimeException("请求头为空");
        }

        TokenInfo tokenInfo=null;
        try {
            //获取token信息
            tokenInfo = getTokenInfo(authHeader);
        }catch (Exception e) {
            throw new RuntimeException("校验令牌异常");
        }
        // tokenInfo
        exchange.getAttributes().put("tokenInfo",tokenInfo);
        return chain.filter(exchange);
    }

    private boolean shouldSkip(String reqPath) {

        for(String skipPath:shouldSkipUrl) {
            if(reqPath.contains(skipPath)) {
                return true;
            }
        }
        return false;
    }

    private TokenInfo getTokenInfo(String authHeader) {
        // 往授权服务发请求 /oauth/check_token
        // 获取token的值
        String token = StringUtils.substringAfter(authHeader, "bearer ");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //必须 basicAuth clienId clientSecret
        headers.setBasicAuth(MDA.clientId, MDA.clientSecret);

        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("token", token);

        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, headers);

        ResponseEntity<TokenInfo> response = restTemplate.exchange(MDA.checkTokenUrl, HttpMethod.POST, entity, TokenInfo.class);

        return response.getBody();
    }
}

常量类:

java 复制代码
public class MDA {
    public static final String clientId = "gateway-server";

    public static final String clientSecret = "123123";

    public static final String checkTokenUrl = "http://auth-server/oauth/check_token";

}

3产品微服务

我启动端口为:8084

4.订单微服务

我启动端口为:8082

5.开始测试单点登录

  1. 比如哪个单点登录接口处理完业务相关逻辑等,然后请求我们的授权服务-通过密码模式获取到access_token
  2. 使用同一access_token,请求网关获取订单信息

    3.使用同一access_token,请求网关获取商品信息

    这样就完成我们的单点登录啦。
相关推荐
sailing-data3 分钟前
【SE BT】BR/DER协议
物联网·架构
one_love_zfl17 分钟前
java面试-微服务组件篇
java·微服务·面试
吴爃44 分钟前
Spring Boot 项目在 K8S 中的打包、部署与运维发布实践
运维·spring boot·kubernetes
a8a3021 小时前
Laravel8.x新特性全解析
java·spring boot·后端
白露与泡影1 小时前
Spring Boot 完整流程
java·spring boot·后端
Ghost Face...1 小时前
LS2K1000启动全链路架构解析
架构
七夜zippoe1 小时前
工业物联网数据架构设计
物联网·架构·数据·工业物联网·dolphindb
黄俊懿2 小时前
MySQL主从复制:从“异步“到“GTID“,数据同步的进化之路
数据库·sql·mysql·oracle·架构·dba·db
Sam_Deep_Thinking2 小时前
中小团队需要一个资源微服务
java·微服务·架构
星辰_mya2 小时前
异地多活:单元化架构设计
微服务·架构