springcloud整合nacos、sentinal、springcloud-gateway,springboot security、oauth2總結(jié)

源碼地址:下載地址
使用該架構(gòu)的項(xiàng)目地址:下載地址

下面教大家整合nacos、sentinal、springcloud-gateway,springboot security、oauth2做一個(gè)分布式架構(gòu)

1、第一步整合nacos

1、下載alibaba的nacos 下載地址,然后使用單機(jī)模式啟動(dòng)nacos

sh startup.sh -m standalone

啟動(dòng)之后登錄 http://localhost:8848/nacos/#/login ,賬號(hào)密碼都是默認(rèn)的nacos。

2、第二步建立業(yè)務(wù)項(xiàng)目結(jié)構(gòu)

項(xiàng)目結(jié)構(gòu)圖片

3、第三步建立項(xiàng)目的入口(網(wǎng)關(guān)服務(wù))

首先入口接口網(wǎng)關(guān)模塊

pom文件

  <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.xyw.code</groupId>
        <artifactId>xptx-gateway</artifactId>
        <version>1.0.0</version>
    </parent>
    <groupId>com.xyw.code</groupId>
    <artifactId>xptx-spring-gateway</artifactId>
    <version>1.0.0</version>
    <name>xptx-spring-cloud-gateway</name>
    <description>spring-cloud-gateway網(wǎng)關(guān)服務(wù)</description>

    <properties>
        <java.version>1.8</java.version>
        <swagger2.version>2.8.0</swagger2.version>
        <xptx.version>1.0.0</xptx.version>
        <spring-boot.version>2.1.8.RELEASE</spring-boot.version>
    </properties>


    <dependencies>
        <!--nacos注冊(cè)中心客戶端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--nacos配置中心客戶端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--gateway 網(wǎng)關(guān)依賴,內(nèi)置webflux 依賴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <dependency>
            <groupId>com.xyw.code</groupId>
            <artifactId>xptx-common-core</artifactId>
            <version>${xptx.version}</version>
        </dependency>
        <dependency>
            <groupId>com.xyw.code</groupId>
            <artifactId>xptx-common-redis</artifactId>
            <version>${xptx.version}</version>
        </dependency>
        <dependency>
            <groupId>com.xyw.code</groupId>
            <artifactId>xptx-auth-client</artifactId>
            <version>${xptx.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>javax.servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

<font color=red>
集成網(wǎng)關(guān)的時(shí)候有個(gè)坑注意下,因?yàn)榫W(wǎng)關(guān)自帶web,所以集成網(wǎng)關(guān)的時(shí)候不能攜帶任何api或者web的模塊,不會(huì)啟動(dòng)會(huì)報(bào)錯(cuò)
</font>


設(shè)置好入口之后修改下application.yml文件設(shè)置下網(wǎng)關(guān)服務(wù)的入口和業(yè)務(wù)服務(wù)的入口

  routes:
    #        基礎(chǔ)服務(wù)
    - id: xptx-system-base-server
      # lb代表從注冊(cè)中心獲取服務(wù),且已負(fù)載均衡方式轉(zhuǎn)發(fā)
      uri: lb://xptx-system-base-server
      predicates: # 路由條件,Predicate 接受一個(gè)輸入?yún)?shù),返回一個(gè)布爾值結(jié)果
        - Path=/sys/**
      filters:
        - SwaggerHeaderFilter
        - StripPrefix=1
        # 降級(jí)配置
        - name: Hystrix
          args:
            name: fallback
            fallbackUri: forward:/fallback
    #        授權(quán)服務(wù)
    - id: xptx-auth
      uri: http://localhost:8001
      predicates:
        - Path=/auth/**
      filters:
        - ImageCodeFilter
        - RemoveRequestHeader=Origin
        - StripPrefix=1
        # 降級(jí)配置
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/fallback

然后有一點(diǎn)要注意的
網(wǎng)關(guān)和業(yè)務(wù)數(shù)據(jù)可以通過兩種方式鑒權(quán)

1、服務(wù)器鑒權(quán)

首先業(yè)務(wù)數(shù)據(jù)集成xptx-common-auth模塊拿到鑒權(quán)注解。之后的鑒權(quán)可以通過@PreAuthorize來實(shí)現(xiàn)。

例子

/**
     * 根據(jù)id刪除菜單
     *
     * @param id
     * @return
     */
    @ApiOperation("刪除菜單")
    @PreAuthorize("hasAuthority('sys:menu:delete')")
    @SysOperateLog(descrption = "刪除菜單")
    @DeleteMapping("/{id}")
    public R deleteMenu(@PathVariable("id") Integer id) {
        return menuService.removeMenuById(id);
    }
2、網(wǎng)關(guān)那里鑒權(quán)

在網(wǎng)關(guān)那里實(shí)現(xiàn)一個(gè)全局?jǐn)r截器去鑒權(quán)

package com.prex.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * 調(diào)用鑒權(quán)
 */
@Slf4j
@Component
public class AuthSignatureFilter implements GlobalFilter, Ordered {

    // 排除過濾的 uri 地址
    private static final String[] WHITE_LIST = {"/*/v2/api-docs", "/user/register", "/swagger-ui.html",
            "/swagger-resources/**",
            "/*/api-docs",
            "/api/socket/**",
            "/log"};

    private AntPathMatcher antPathMatcher = new AntPathMatcher();


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

        ServerHttpRequest request = exchange.getRequest();
        String uriPath = request.getPath().toString();

        log.info("url:{}", uriPath);
        boolean action = false;
        for (String url : WHITE_LIST) {
            if (antPathMatcher.match(url, uriPath)) {
                action = true;
                break;
            }
        }
        // 跳過不需要驗(yàn)證的路徑
        if (action) {
            return chain.filter(exchange);
        }

        String token = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (null == token || token.isEmpty()) {
            ServerHttpResponse response = exchange.getResponse();
            //當(dāng)請(qǐng)求不攜帶Token或者token為空時(shí),直接設(shè)置請(qǐng)求狀態(tài)碼為401,返回
            InetSocketAddress remoteAddress = request.getRemoteAddress();
            String clientIp = Objects.requireNonNull(remoteAddress).getAddress().getHostAddress();
            log.info("非法請(qǐng)求,客戶端IP:" + clientIp + "URL:" + request.getPath());
            JSONObject message = new JSONObject();
            message.put("code", HttpStatus.UNAUTHORIZED.value());
            message.put("msg", "非法請(qǐng)求");
            byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = response.bufferFactory().wrap(bits);
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //指定編碼,否則在瀏覽器中會(huì)中文亂碼
            response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
            return response.writeWith(Mono.just(buffer));

        }
        ServerHttpRequest authorization = request.mutate().headers(httpHeaders -> {
            httpHeaders.add("Authorization", token);
        }).build();
        ServerWebExchange serverWebExchange = exchange.mutate().request(authorization).build();
        return chain.filter(serverWebExchange);
    }

    @Override
    public int getOrder() {
        return -200;
    }
}

全局?jǐn)r截器調(diào)用的是鑒權(quán)客戶端,然后鑒權(quán)客戶端可以通過feign去調(diào)用鑒權(quán)服務(wù)端來判斷用戶是否擁有這個(gè)權(quán)限。這就是大致簡(jiǎn)單的整合流程。

4、第三步建立項(xiàng)目的認(rèn)證服務(wù)

認(rèn)證服務(wù)分為兩部分:

1:

一部分把認(rèn)證服務(wù)作為一個(gè)jar包,目的是作為一個(gè)認(rèn)證客戶端給第三方引用(<font color='red'>這里有個(gè)坑,千萬不能加入<artifactId>spring-boot-maven-plugin</artifactId>這個(gè)插件,因?yàn)檫@個(gè)插件會(huì)導(dǎo)致maven多moudle依賴找不到引入jar包依賴</font>)。

2:

就是一個(gè)鑒權(quán)服務(wù),里面整合了spring-security和spring-oauth2。這兩個(gè)大致作用是spring-security用來存儲(chǔ)用戶,通過用戶鑒權(quán)來獲取token。但是有些時(shí)候第三方服務(wù)想調(diào)用我們的接口,那我們?yōu)榱瞬惶峁┳约旱馁~號(hào)密碼給別人,因此就使用了oauth2,通過提供client_id和serect的方式來獲取token,從而來被允許調(diào)用我們的服務(wù)。

獲取token的鏈接:http://localhost:8002/auth/oauth/token?username=admin&password=admin&t=1571628400280&code=fzbz&grant_type=password&scope=server

總結(jié)

分布式項(xiàng)目整合一切以網(wǎng)關(guān)為入口,然后網(wǎng)關(guān)前綴分為業(yè)務(wù)項(xiàng)目的前綴和認(rèn)證服務(wù)器前綴。最后網(wǎng)關(guān)還會(huì)有一個(gè)全局?jǐn)r截器去攔截認(rèn)證請(qǐng)求

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容