Spring Security OAuth2.0(22):分布式系统授权-搭建网关

本章代码已提交至Gitee: https://gitee.com/lengcz/distributed-security01.git

文章目录

网关

网关整合OAuth2.0 有两种思路,一种是认证服务器生成jwt令牌,所有请求统一在网关层验证,判断权限等操作;另一种是由各资源服务器处理,网关只做请求转发。

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

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

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

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

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

  • 用户授权拦截(看当前用户是否有权限访问该资源)
  • 将用户信息存储金当前线程上下文(有利于后续业务逻辑随时获取当前用户信息)

创建网关

  1. 创建网关 distributed-security-gateway

pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>distributed-security</artifactId>
        <groupId>com.it2.security</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>distributed-security-gateway</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-javanica</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.interceptor</groupId>
            <artifactId>javax.interceptor-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

</project>

application.properties

properties 复制代码
spring.application.name=gateway-server
server.port=53010
spring.main.allow-bean-definition-overriding = true

logging.level.root = info
logging.level.org.springframework = info

zuul.retryable = true
zuul.ignoredServices = *
zuul.add-host-header = true
zuul.sensitiveHeaders = *

zuul.routes.uaa-service.stripPrefix = false
zuul.routes.uaa-service.path = /uaa/**

zuul.routes.order-service.stripPrefix = false
zuul.routes.order-service.path = /order/**

eureka.client.serviceUrl.defaultZone = http://localhost:53000/eureka/
eureka.instance.preferIpAddress = true
eureka.instance.instance-id = ${spring.application.name}:${server.port}
management.endpoints.web.exposure.include = refresh,health,info,env

feign.hystrix.enabled = true
feign.compression.request.enabled = true
feign.compression.request.mime-types[0] = text/xml
feign.compression.request.mime-types[1] = application/xml
feign.compression.request.mime-types[2] = application/json
feign.compression.request.min-request-size = 2048
feign.compression.response.enabled = true
feign.httpclient.connection-timeout=10000

启动类

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy  //网关zuul代理
@EnableDiscoveryClient  //需要从注册中心拿地址
public class GatewayServer {

    public static void main(String[] args) {
        SpringApplication.run(GatewayServer.class, args);
    }
}

统一认证服务(UAA)与统一用户服务都是网关下微服务,需要在网关下新增路由配置

properties 复制代码
zuul.routes.uaa-service.stripPrefix = false
zuul.routes.uaa-service.path = /uaa/**

zuul.routes.order-service.stripPrefix = false
zuul.routes.order-service.path = /order/**

配置ResourceServerConfig

java 复制代码
package com.it2.security.distributed.gateway.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

@Configuration
public class ResourceServerConfig {

    public static final String RESOURCE_ID ="res1";

    @Autowired
    private TokenStore tokenStore;

    //uaa资源服务配置
    @Configuration
    @EnableResourceServer
    public class UAAServerConfig extends ResourceServerConfigurerAdapter{
        @Autowired
        private TokenStore tokenStore;

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(RESOURCE_ID) //资源id
                    .tokenStore(tokenStore)  //自己验证令牌
//                .tokenServices(tokenService()) //验证令牌的服务
                    .stateless(true);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/uaa/**").permitAll();
        }

    }

    //uaa资源服务配置
    @Configuration
    @EnableResourceServer
    public class OrderServerConfig extends ResourceServerConfigurerAdapter{
        @Autowired
        private TokenStore tokenStore;

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(RESOURCE_ID) //资源id
                    .tokenStore(tokenStore)  //自己验证令牌
//                .tokenServices(tokenService()) //验证令牌的服务
                    .stateless(true);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/order/**").access("#oauth2.hasScope('ROLE_API')");
        }

    }

    //配置其他资源服务

}

上面定义了两个微服务的资源,其中:

UAAServerConfig指定了若请求匹配/uaa/网关不进行拦截。
OrderServerConfig指定了若请求匹配/order/
,也就是访问统一用户服务,接入客户端需要有scope中包含read,并且authorities权限中需要包含ROLE_USER

由于res1这个接入客户端,read包括ROLE_ADMIN,ROLE_USER,ROLE_API三个权限。

安全配置

这个资源服务同样也需要接入安全配置。

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    //配置安全拦截机制
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").permitAll().and().csrf().disable();
    }


}
相关推荐
存在的五月雨1 小时前
SpringBoot后端限制重复提交
java·spring boot·后端
Sam_Deep_Thinking1 小时前
一次线程池线上故障复盘:四层防线如何避免数据丢失
java·面试·程序员
paopaokaka_luck1 小时前
基于Springboot3+Vue3的宠物殡葬管理系统(webSocket实时通讯、接入腾讯地图、支付宝沙盒支付、Echarts图形化分析)
java·开发语言·网络·后端
卷无止境1 小时前
Python 中基于 Qt 的 GUI 库授权方式全解析
后端·python
程序员爱钓鱼1 小时前
Rust 注释与文档注释详解:从代码说明到 cargo doc
后端·rust
前鼻音太阳熊2 小时前
【MES系统】MES为什么需要SSE?从设备实时监控谈Spring Boot流式推送设计
java·spring boot·后端
Lhappy嘻嘻2 小时前
网络初识|基础入门:局域网广域网、IP 端口、TCP/IP 五层模型与封装解封装全过程
java·开发语言·网络·笔记·网络协议·tcp/ip
卷无止境2 小时前
Guardrails.ai:为大语言模型加一道"安全阀"
后端·python
Java面试题总结2 小时前
区间树:反向映射的前置数据结构
java·前端·数据结构