从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

紧接上文《从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(二) (mini-cloud) 创建项目以及搭建源码启动版nacos 注册中心》今天主要来一步步详细聊一下如何搭建认证,中心,也就是下图的auth2.0认证服务

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

今天涉及的方面比较多,也会捎带聊聊一些内部原理以及代码等,所以分为上,中,下三部分来说

全片主要依照下面流程来说,主要也是一个从无到有,从粗到细的一个过程,尽量贴近大家一个开发流程,本文介绍的也不是最终的版本,在后面会有一些重构代码的文章,前期不会做到一步到位,直接贴上完善代码和一步步变为完善我觉得后者对大家帮助更大,后面会将源码公开到github

好了,先介绍一下整体文章流程

##1.创建authentication-center 服务
##2.将authentication-center 服务集成入spring cloud nacos注册中心
##3.选择oauth2 认证模式,分离认证服务器以及资源服务器,设计下沉式资源端认证模式
##4.按照spring 官方内存式认证demo 搭建oauth2 client 认证
##5.添加测试服务module 并集成如spring cloud nacos 中
##6.测试服务 作为resource server 进行认证测试
##7.将配置文件参数纳入nacos 配置中心进行管理
##8.将内存式认证改为实际redis 以及clientdetail ,userdetail 为数据库中获取
##9.将demo 权限认证改为根据当前登陆用户角色动态校验权限
##10.抽取认证服务器与资源服务器共通部分变为common module
##11.应用common 模块重构代码再次校验认证

 

1.创建authentication-center 服务

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

我们在mini-cloud 目录下新建一个module  ,起名为authentication-center 即认证中心,这个专门用来认证获取access_token ,reflush_token ,check_token 等,创建完module之后,我们将该服务集成进入到spring cloud nacos 体系

2.将authentication-center 服务集成入spring cloud nacos注册中心

需要相关改动的地方有如下几个文件,给出代码

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

MiniCloudAuthApplication.java
package com.minicloud.authentication;

import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;

/**
 * @Author alan.wang
 * @date: 2022-01-17 10:18
 */
@SpringCloudApplication
public class MiniCloudAuthApplication {

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

bootstrap.yml

server:
  port: 8800

spring:
  application:
    name: @artifactId@
  cloud:
    nacos:
      discovery:
        server-addr: ${NACOS_HOST:127.0.0.1}:${NACOS_PORT:8848}
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yml
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
  profiles:
    active: @profiles.active@

pom.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>mini-cloud</artifactId>
        <groupId>org.mini-cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>authentication-center</artifactId>


    <dependencies>
        <!--注册中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--配置中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--安全模块 -->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
        </dependency>
        <!--web 模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
        </dependency>
        <dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>nimbus-jose-jwt</artifactId>
        </dependency>
    </dependencies>
</project>

其实但是spring cloud 集成只需要

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

另外之前的mini-cloud 根pom.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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.mini-cloud</groupId>
    <artifactId>mini-cloud</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>register-center</module>
        <module>authentication-center</module>
        <module>mini-cloud-tester</module>
    </modules>

    <properties>
        <nacos-version>1.4.1</nacos-version>
        <nacos-name>com.alibaba.nacos</nacos-name>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- Compiler settings properties -->
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <!-- Maven properties -->
        <maven.test.skip>false</maven.test.skip>
        <maven.javadoc.skip>true</maven.javadoc.skip>
        <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
        <!-- Exclude all generated code -->
        <sonar.jacoco.itReportPath>${project.basedir}/../test/target/jacoco-it.exec</sonar.jacoco.itReportPath>
        <sonar.exclusions>file:**/generated-sources/**,**/test/**</sonar.exclusions>
        <security.oauth.version>2.3.6.RELEASE</security.oauth.version>

        <!-- plugin version -->
        <versions-maven-plugin.version>2.2</versions-maven-plugin.version>
        <dependency-mediator-maven-plugin.version>1.0.2</dependency-mediator-maven-plugin.version>
        <clirr-maven-plugin.version>2.7</clirr-maven-plugin.version>
        <maven-enforcer-plugin.version>1.4.1</maven-enforcer-plugin.version>
        <maven-compiler-plugin.version>3.5.1</maven-compiler-plugin.version>
        <maven-javadoc-plugin.version>2.10.4</maven-javadoc-plugin.version>
        <maven-source-plugin.version>3.0.1</maven-source-plugin.version>
        <maven-pmd-plugin.version>3.8</maven-pmd-plugin.version>
        <apache-rat-plugin.version>0.12</apache-rat-plugin.version>
        <maven-resources-plugin.version>3.0.2</maven-resources-plugin.version>
        <coveralls-maven-plugin.version>4.3.0</coveralls-maven-plugin.version>
        <jacoco-maven-plugin.version>0.7.8</jacoco-maven-plugin.version>
        <maven-surefire-plugin.version>2.20</maven-surefire-plugin.version>
        <findbugs-maven-plugin.version>3.0.4</findbugs-maven-plugin.version>
        <sonar-maven-plugin.version>3.0.2</sonar-maven-plugin.version>
        <maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
        <maven-failsafe-plugin.version>2.19.1</maven-failsafe-plugin.version>
        <maven-assembly-plugin.version>3.0.0</maven-assembly-plugin.version>
        <maven-checkstyle-plugin.version>3.1.1</maven-checkstyle-plugin.version>
        <!-- dependency version related to plugin -->
        <extra-enforcer-rules.version>1.0-beta-4</extra-enforcer-rules.version>
        <p3c-pmd.version>1.3.0</p3c-pmd.version>

        <!-- dependency version -->
        <spring-cloud-starter-netflix-hystrix.version>2.2.5.RELEASE</spring-cloud-starter-netflix-hystrix.version>
        <spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
        <spring-boot-dependencies.version>2.2.6.RELEASE</spring-boot-dependencies.version>
        <servlet-api.version>3.0</servlet-api.version>
        <commons-lang3.version>3.4</commons-lang3.version>
        <commons-io.version>2.2</commons-io.version>
        <commons-collections.version>3.2.2</commons-collections.version>
        <commons-logging.version>1.2</commons-logging.version>
        <commons-dbcp.version>1.4</commons-dbcp.version>
        <commons-cli.version>1.2</commons-cli.version>
        <slf4j-api.version>1.7.7</slf4j-api.version>
        <logback.version>1.2.3</logback.version>
        <log4j.version>2.13.3</log4j.version>
        <httpcore.version>4.4.1</httpcore.version>
        <httpclient.version>4.5</httpclient.version>
        <httpasyncclient.version>4.1.3</httpasyncclient.version>
        <mysql-connector-java.version>8.0.16</mysql-connector-java.version>
        <derby.version>10.14.2.0</derby.version>
        <cglib-nodep.version>2.1</cglib-nodep.version>
        <jcip-annotations.version>1.0</jcip-annotations.version>
        <jackson-core.version>2.10.4</jackson-core.version>
        <jackson-databind.version>2.10.4</jackson-databind.version>
        <jackson-core-asl.version>1.9.13</jackson-core-asl.version>
        <jjwt.version>0.11.2</jjwt.version>
        <netty-all.version>4.1.42.Final</netty-all.version>
        <netty-common.version>4.1.31.Final</netty-common.version>
        <mina-core.version>2.0.0-RC1</mina-core.version>
        <guava.version>24.1.1-jre</guava.version>
        <javatuples.version>1.2</javatuples.version>
        <commonOkHttp.version>0.4.1</commonOkHttp.version>
        <grpc-java.version>1.24.0</grpc-java.version>
        <proto-google-common-protos.version>1.17.0</proto-google-common-protos.version>
        <protobuf-java.version>3.8.0</protobuf-java.version>
        <protoc-gen-grpc-java.version>1.24.0</protoc-gen-grpc-java.version>
        <hessian.version>4.0.63</hessian.version>
        <reflections.version>0.9.11</reflections.version>
        <mockito-all.version>1.10.19</mockito-all.version>
        <hamcrest-all.version>1.3</hamcrest-all.version>
        <prometheus-simpleclient.version>0.5.0</prometheus-simpleclient.version>
        <tomcat-embed-jasper.version>9.0.37</tomcat-embed-jasper.version>
        <truth.version>0.30</truth.version>
        <HikariCP.version>3.4.2</HikariCP.version>
        <jraft-core.version>1.3.5</jraft-core.version>
        <rpc-grpc-impl.version>1.3.5</rpc-grpc-impl.version>

    </properties>
    <!-- 管理依赖版本号,子项目不会默认依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <!-- Import dependency management from Spring Boot -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot-dependencies.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Internal libs -->
            <dependency>
                <groupId>${nacos-name}</groupId>
                <artifactId>nacos-config</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${nacos-name}</groupId>
                <artifactId>nacos-core</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${nacos-name}</groupId>
                <artifactId>nacos-naming</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${nacos-name}</groupId>
                <artifactId>nacos-api</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>nacos-client</artifactId>
                <version>${nacos-version}</version>
            </dependency>

            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>nacos-common</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>nacos-cmdb</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>nacos-console</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>nacos-distribution</artifactId>
                <version>${nacos-version}</version>
            </dependency>

            <dependency>
                <groupId>${nacos-name}</groupId>
                <artifactId>nacos-address</artifactId>
                <version>${nacos-version}</version>
            </dependency>

            <dependency>
                <groupId>${nacos-name}</groupId>
                <artifactId>nacos-istio</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>nacos-consistency</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${nacos-name}</groupId>
                <artifactId>nacos-auth</artifactId>
                <version>${nacos-version}</version>
            </dependency>
            <dependency>
                <groupId>${nacos-name}</groupId>
                <artifactId>nacos-sys</artifactId>
                <version>${nacos-version}</version>
            </dependency>

            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>${servlet-api.version}</version>
                <scope>provided</scope>
            </dependency>

            <!-- HikariCP -->
            <dependency>
                <groupId>com.zaxxer</groupId>
                <artifactId>HikariCP</artifactId>
                <version>${HikariCP.version}</version>
            </dependency>

            <!-- hessian -->

            <dependency>
                <groupId>com.caucho</groupId>
                <artifactId>hessian</artifactId>
                <version>${hessian.version}</version>
            </dependency>

            <!-- Apache commons -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>${commons-lang3.version}</version>
            </dependency>

            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>${commons-io.version}</version>
            </dependency>

            <dependency>
                <groupId>commons-collections</groupId>
                <artifactId>commons-collections</artifactId>
                <version>${commons-collections.version}</version>
            </dependency>

            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>${commons-logging.version}</version>
            </dependency>

            <dependency>
                <groupId>commons-dbcp</groupId>
                <artifactId>commons-dbcp</artifactId>
                <version>${commons-dbcp.version}</version>
            </dependency>

            <dependency>
                <groupId>commons-cli</groupId>
                <artifactId>commons-cli</artifactId>
                <version>${commons-cli.version}</version>
            </dependency>

            <!-- Logging libs -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j-api.version}</version>
            </dependency>

            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>${logback.version}</version>
            </dependency>

            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>${logback.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>${log4j.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>${log4j.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-slf4j-impl</artifactId>
                <version>${log4j.version}</version>
            </dependency>

            <!-- HTTP client libs -->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpcore</artifactId>
                <version>${httpcore.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>${httpclient.version}</version>
                <exclusions>
                    <exclusion>
                        <artifactId>commons-logging</artifactId>
                        <groupId>commons-logging</groupId>
                    </exclusion>
                </exclusions>
            </dependency>

            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpasyncclient</artifactId>
                <version>${httpasyncclient.version}</version>
            </dependency>

            <!-- JDBC libs -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql-connector-java.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.derby</groupId>
                <artifactId>derby</artifactId>
                <version>${derby.version}</version>
            </dependency>

            <!-- JRaft -->
            <dependency>
                <groupId>com.alipay.sofa</groupId>
                <artifactId>jraft-core</artifactId>
                <version>${jraft-core.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.alipay.sofa</groupId>
                        <artifactId>bolt</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.apache.logging.log4j</groupId>
                        <artifactId>log4j-api</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.apache.logging.log4j</groupId>
                        <artifactId>log4j-core</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.apache.logging.log4j</groupId>
                        <artifactId>log4j-slf4j-impl</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.apache.logging.log4j</groupId>
                        <artifactId>log4j-jcl</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

            <dependency>
                <groupId>com.alipay.sofa</groupId>
                <artifactId>rpc-grpc-impl</artifactId>
                <version>${rpc-grpc-impl.version}</version>
            </dependency>

            <!-- Third-party libs -->
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib-nodep</artifactId>
                <version>${cglib-nodep.version}</version>
            </dependency>

            <dependency>
                <groupId>net.jcip</groupId>
                <artifactId>jcip-annotations</artifactId>
                <version>${jcip-annotations.version}</version>
            </dependency>

            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
                <version>${jackson-core.version}</version>
            </dependency>

            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jackson-databind.version}</version>
            </dependency>
            <dependency>
                <groupId>org.codehaus.jackson</groupId>
                <artifactId>jackson-core-asl</artifactId>
                <version>${jackson-core-asl.version}</version>
            </dependency>

            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt-api</artifactId>
                <version>${jjwt.version}</version>
            </dependency>
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt-impl</artifactId>
                <version>${jjwt.version}</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt-jackson</artifactId>
                <version>${jjwt.version}</version>
                <scope>runtime</scope>
            </dependency>

            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-all</artifactId>
                <version>${netty-all.version}</version>
            </dependency>

            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-common</artifactId>
                <version>${netty-common.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.mina</groupId>
                <artifactId>mina-core</artifactId>
                <version>${mina-core.version}</version>
            </dependency>

            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>${guava.version}</version>
            </dependency>

            <dependency>
                <groupId>org.javatuples</groupId>
                <artifactId>javatuples</artifactId>
                <version>${javatuples.version}</version>
            </dependency>

            <dependency>
                <groupId>com.github.keran213539</groupId>
                <artifactId>commonOkHttp</artifactId>
                <version>${commonOkHttp.version}</version>
                <scope>test</scope>
            </dependency>

            <!-- gRPC dependency start -->

            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty-shaded</artifactId>
                <version>${grpc-java.version}</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
                <version>${grpc-java.version}</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
                <version>${grpc-java.version}</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>protoc-gen-grpc-java</artifactId>
                <version>${grpc-java.version}</version>
                <type>pom</type>
            </dependency>
            <dependency>
                <groupId>com.google.api.grpc</groupId>
                <artifactId>proto-google-common-protos</artifactId>
                <version>${proto-google-common-protos.version}</version>
            </dependency>

            <!-- gRPC dependency end -->

            <dependency>
                <groupId>com.google.protobuf</groupId>
                <artifactId>protobuf-java</artifactId>
                <version>${protobuf-java.version}</version>
            </dependency>

            <dependency>
                <groupId>org.reflections</groupId>
                <artifactId>reflections</artifactId>
                <version>${reflections.version}</version>
            </dependency>

            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-all</artifactId>
                <version>${mockito-all.version}</version>
            </dependency>

            <dependency>
                <groupId>org.hamcrest</groupId>
                <artifactId>hamcrest-all</artifactId>
                <version>${hamcrest-all.version}</version>
            </dependency>

            <dependency>
                <groupId>io.prometheus</groupId>
                <artifactId>simpleclient</artifactId>
                <version>${prometheus-simpleclient.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
                <version>${tomcat-embed-jasper.version}</version>
            </dependency>

            <dependency>
                <groupId>com.google.truth</groupId>
                <artifactId>truth</artifactId>
                <version>${truth.version}</version>
            </dependency>

            <!--spring cloud alibaba-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-jwt</artifactId>
                <version>1.1.0.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.nimbusds</groupId>
                <artifactId>nimbus-jose-jwt</artifactId>
                <version>8.2.1</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.security.oauth.boot</groupId>
                <artifactId>spring-security-oauth2-autoconfigure</artifactId>
                <version>2.2.1.RELEASE</version>
            </dependency>
            <!--稳定版本,替代spring security bom内置-->
            <dependency>
                <groupId>org.springframework.security.oauth</groupId>
                <artifactId>spring-security-oauth2</artifactId>
                <version>${security.oauth.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
                <version>${spring-cloud-starter-netflix-hystrix.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <distributionManagement>
        <snapshotRepository>
            <!-- 这里的ID一定要在maven setting文件中存在于server下的ID -->
            <id>sona</id>
            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
        </snapshotRepository>
        <repository>
            <id>sona</id>
            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
        </repository>
    </distributionManagement>

    <profiles>
        <profile>
            <id>dev</id>
            <properties>
                <!-- 环境标识,需要与配置文件的名称相对应 -->
                <profiles.active>dev</profiles.active>
            </properties>
            <activation>
                <!-- 默认环境 -->
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>test</id>
            <properties>
                <profiles.active>test</profiles.active>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <profiles.active>prod</profiles.active>
            </properties>
        </profile>
    </profiles>
    <build>
        <finalName>${project.name}</finalName>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <pluginManagement>

            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

            </plugins>
        </pluginManagement>

    </build>
</project>

注册中心的application 改了个名,统一了一下,由nacos改成了MiniCloudRegisterApplication

好了测试一下是否集成入了spring cloud nacos ,先启动nacos 注册中心,再启动认证中心

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

 然后访问http://localhost:8848/nacos/ 控制台

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

发现确实刚刚搭建的认证服务以及集成入了nacos  

 3.选择oauth2 认证模式,分离认证服务器以及资源服务器,设计下沉式资源端认证模式

这里涉及到一些理论内容,我画了俩图描述一下什么是认证服务,什么是资源服务,他俩的关系是什么,理解起来容易一些

           认证服务与资源服务

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

     

               认证服务与资源服务关联

 从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

 白话总结一下:

认证服务:主要就是我们的认证中心,所有客户端访问资源服务的时候,资源服务都会内部访问一下认证服务去校验是否有权利

资源服务:就是被访问的接口,侠义上web的话可以说是我们的controller 的url

想详细了解的可以访问spring auth2.0官网以及官网提供的demo直接运行

auth2.0官网介绍:https://projects.spring.io/spring-security-oauth/docs/oauth2.html

auth2.0 默认支持以下认证模式 通过访问参数grant_type 区分

有兴趣得可以了解下,我们这里简单说明一下

authorization code:授权码模式,比较安全,但是仅能用在web 项目,需要有页面url

client_credentials: 客户端模式,这里主要就是针对app 或者某一服务得认证,例如微信平台对我们某一应用,阿里云oss 对我们某一应用等,这里不太适合我们普遍的用户通过账号密码登陆厂家

password:用户名密码模式,就是我们常用的本站用户通过用户名密码等登陆的场景,本文主要选取该模式,以后会说一下如何自定义授权模式,做到支持自己需要的授权,不在本文范围内

虽说我们选取的是password模式,但其实依然需要对client 认证做支持,因为我们认证中心以后可能会需要支持其他外部服务的接入,所以还是要对每个服务有一个clientId以及共通端的资源权限认定

4.按照spring 官方内存式认证demo 搭建oauth2 client 认证

我们开发任何功能,一般都会想用最简单的demo 完成最小闭环保证先跑起来,我们也这样,直接拿官网demo改一下,先保证跑起来

 auth2.0官网demo地址:GitHub - jgrandja/spring-security-oauth-2-4-migrate

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

 认证服务一般就需要做两件事就可以了

1. 继承  AuthorizationServerConfigurerAdapter 并开启 @EnableAuthorizationServer

2.继承  WebSecurityConfigurerAdapter 并开启 @EnableWebSecurity

1 是为了自定义加入自己的server端的自定义bean,比如clientservice ,.userdetailservice

2 是为了注入web服务本身需要的拦截器或者需要拦截的url等

闲话少说,本身代码很少也都是内存模式运行的,直接上代码,代码上我也做了详细注释

我们只要添加两个文件即可

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

AuthorizationServerConfig.java
/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.minicloud.authentication.config;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;

import javax.annotation.Resource;


/**
 * @author alan.wang
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;


    /**
     * @desc :注入client 相关内如,内存模式直接注入模拟的一个client端
     * withClient :clientId
     * secret: clientId对应密码,记得spring5.0之后前面要加上{加密方式}密文
     * authorizedGrantTypes:接受哪些授权模式,参数 grant_type 区分
     * authorities:具有哪些权限,一般针对api级别,基本没用上
     * scopes:读写级别
     * */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("test-auth-client").secret("{bcrypt}" + new BCryptPasswordEncoder().encode("123"))
                .authorizedGrantTypes("authorization_code", "refresh_token", "client_credentials", "password")
                .authorities("autho2").scopes("read", "write");


    }

    /**
     * @desc: 设置auth2.0本身开放的访问权限
     * 这里对/oauth/check_token 开放了表单提交权限
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {

        security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients();
    }

    /**
     * @desc: 主要是对endpoints(框架本身的url路径)注入自定义service
     * 这里对注入了默认的userDetailsService,authenticationManager,
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
                .userDetailsService(userDetailsService)
                .authenticationManager(authenticationManager);


    }




}

 

SecurityConfig.java
package com.minicloud.authentication.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * @Author alan.wang
 * @date: 2022-01-17 14:01
 */

@Configuration
@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {


    /**
     * @desc:对本web 服务的url拦截设置
     * 这里开放了所有/oauth/** 的权限,因为是框架的路径
     * */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .requestMatchers().anyRequest()
                .and()
                .authorizeRequests()
                .antMatchers("/oauth/**").permitAll();
    }

    /**
     * @desc:注入默认的AuthenticationManager bean
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    /**
     * @desc:注入默认的UserDetailsService bean 并添加两个测试用户
     * username:用户名
     * password:密码,同样注意标明{加密方式}密文
     * roles:角色,可以实多个
     *
     */
    @Bean
    public UserDetailsService userDetailsService()   {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.builder().username("user1").password("{bcrypt}" + new BCryptPasswordEncoder().encode("123")).roles("USER").build());
        manager.createUser(User.builder().username("admin").password("{bcrypt}" + new BCryptPasswordEncoder().encode("123")).roles("USER", "ADMIN").build());
        return manager;
    }

    /**
     * @desc:注入 PasswordEncoder 加密器
     * PasswordEncoderFactories.createDelegatingPasswordEncoder() 默认为bcrypt 加密
     *
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }


}

代码添加完毕之后重启认证中心服务来验证一下

我用的是user1 ,记得clientId 和密码都对应上,

http://localhost:8800/oauth/token?username=user1&password=123&grant_type=password&scope=read&client_id=test-auth-client&client_secret=123

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

ok,看见已经正常返回 access_token,与reflush_token ,开始进行下一步

5.添加测试服务module 并集成如spring cloud nacos 中

为了方便,我单独创建一个test module 里面放置所有测试服务相关的服务,为了便于以后测试微服务整体业务,也将测试服务作为一个业务端服务纳入spring cloud nacos

好了我们创建一个测试业务端用来当作资源服务进行整合测试,集成进入spring cloud nacos与上面认证中心集成是一样的,就不多说

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

application.yml

server:
  port: 8900

spring:
  application:
    name: @artifactId@
  cloud:
    nacos:
      discovery:
        server-addr: ${NACOS_HOST:127.0.0.1}:${NACOS_PORT:8848}
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yml
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
  profiles:
    active: @profiles.active@

 pom.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>mini-cloud-tester</artifactId>
        <groupId>org.mini-cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>authentication-center-test</artifactId>


    <dependencies>
        <!--web 模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--注册中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--配置中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--安全模块 -->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
        </dependency>
    </dependencies>
</project>

然后全部启动,看看是否都集成入了nacos

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

进入nacos 控制台查看 http://localhost:8848/nacos/

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

ok,也都没问题,开始将他作为资源服务进行集成

6.测试服务 作为resource server 进行认证测试

对resource server 集成比较简单,只需要继承ResourceServerConfigurerAdapter,然后开启

@EnableResourceServer 即可 ,然后我们创建一个controller ,对该controller url进行校验

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

ResourceServerConfig.java
package com.minicloud.authentication.test.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;

/**
 * @Author alan.wang
 * @date: 2022-01-17 16:26
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {


    /**
     * @desc: 设置需要拦截或者开放的url
     * 这里开放了/oauth/** 框架本身的url
     * 对/test/** 相关需要进行认证
     * */
    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .authorizeRequests()
                .antMatchers("/oauth/**").permitAll()
                .antMatchers("/test/**").authenticated();

    }
}

 

TestController.java
package com.minicloud.authentication.test.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author alan.wang
 * @date: 2022-01-17 15:54
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/hello")
    public ResponseEntity hello(){

        return ResponseEntity.ok("ok");
    }
}

application.yml

server:
  port: 8900

spring:
  application:
    name: @artifactId@
  cloud:
    nacos:
      discovery:
        server-addr: ${NACOS_HOST:127.0.0.1}:${NACOS_PORT:8848}
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yml
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
  profiles:
    active: @profiles.active@

security:
  oauth2:
    resource:
      token-info-uri: http://127.0.0.1:8800/oauth/check_token
    client:
      client-id: test-auth-client
      client-secret: 123
      scope: read

 注意:token-info-uri: 这个是我们认证中心的地址

我们重启test 服务,然后启动测试,我们首先直接访问我们的测试controller url

http://localhost:8900/test/hello 

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

 

{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}

提示很明显,需要提供访问认证

我们现在获取一下access_token

http://localhost:8800/oauth/token?username=user1&password=123&grant_type=password&scope=read&client_id=test-auth-client&client_secret=123

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

{
    "access_token": "6ee98a60-19c6-4843-9f77-954024bc2d9b",
    "token_type": "bearer",
    "refresh_token": "b6bf88c0-1128-4742-af8a-74bc513b7d9b",
    "expires_in": 41459,
    "scope": "read"
}

我们拿到access_token ,然后再访问http://localhost:8900/test/hello

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)

这次正常可以访问资源的url了 ,注意access_token前要加bearer

篇幅太长,本文到此就结束了,我们现在都是在内存环境集成的,真实开发肯定不是这样的,我们一步步来, 下篇我们将内存式变为从redis 和数据库获取数据,达到真实框架能力

 

 

上一篇:ElasticSearch 7.14安装步骤【windows平台】


下一篇:wpf 蒙版实现在控件或者窗口遮罩