【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,请求网关获取商品信息

    这样就完成我们的单点登录啦。
相关推荐
初见0014 分钟前
Spring事务失效的十大陷阱与终极解决方案
后端·架构
gordon~913 分钟前
Spring 的bean是安全的吗
java·安全·spring·bean
疯癫的老码农29 分钟前
【Linux环境下安装】SpringBoot应用环境安装(五)-milvus安装
linux·spring boot·milvus
木易 士心1 小时前
Spring AI 核心架构解析:构建企业级 AI 应用的 Java 新范式
java·spring
IT小番茄2 小时前
储能物联网智能管理平台方案
架构
Kay_Liang2 小时前
大语言模型如何精准调用函数—— Function Calling 系统笔记
java·大数据·spring boot·笔记·ai·langchain·tools
The Open Group2 小时前
从架构到运营:AIOps与O-AA™ 如何实现智能化企业运营
架构
自由的疯2 小时前
Java 如何学习Docker
java·后端·架构
自由的疯2 小时前
Java Docker本地部署
java·后端·架构
摇滚侠2 小时前
Spring Boot 3零基础教程,WEB 开发 内容协商机制 笔记34
java·spring boot·笔记·缓存