紧接上文《从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(二) (mini-cloud) 创建项目以及搭建源码启动版nacos 注册中心》今天主要来一步步详细聊一下如何搭建认证,中心,也就是下图的auth2.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 服务
我们在mini-cloud 目录下新建一个module ,起名为authentication-center 即认证中心,这个专门用来认证获取access_token ,reflush_token ,check_token 等,创建完module之后,我们将该服务集成进入到spring cloud nacos 体系
2.将authentication-center 服务集成入spring cloud nacos注册中心
需要相关改动的地方有如下几个文件,给出代码
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 集成只需要
另外之前的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 注册中心,再启动认证中心
然后访问http://localhost:8848/nacos/ 控制台
发现确实刚刚搭建的认证服务以及集成入了nacos
3.选择oauth2 认证模式,分离认证服务器以及资源服务器,设计下沉式资源端认证模式
这里涉及到一些理论内容,我画了俩图描述一下什么是认证服务,什么是资源服务,他俩的关系是什么,理解起来容易一些
认证服务与资源服务
认证服务与资源服务关联
白话总结一下:
认证服务:主要就是我们的认证中心,所有客户端访问资源服务的时候,资源服务都会内部访问一下认证服务去校验是否有权利
资源服务:就是被访问的接口,侠义上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
认证服务一般就需要做两件事就可以了
1. 继承 AuthorizationServerConfigurerAdapter 并开启 @EnableAuthorizationServer
2.继承 WebSecurityConfigurerAdapter 并开启 @EnableWebSecurity
1 是为了自定义加入自己的server端的自定义bean,比如clientservice ,.userdetailservice
2 是为了注入web服务本身需要的拦截器或者需要拦截的url等
闲话少说,本身代码很少也都是内存模式运行的,直接上代码,代码上我也做了详细注释
我们只要添加两个文件即可
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 和密码都对应上,
ok,看见已经正常返回 access_token,与reflush_token ,开始进行下一步
5.添加测试服务module 并集成如spring cloud nacos 中
为了方便,我单独创建一个test module 里面放置所有测试服务相关的服务,为了便于以后测试微服务整体业务,也将测试服务作为一个业务端服务纳入spring cloud nacos
好了我们创建一个测试业务端用来当作资源服务进行整合测试,集成进入spring cloud nacos与上面认证中心集成是一样的,就不多说
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
进入nacos 控制台查看 http://localhost:8848/nacos/
ok,也都没问题,开始将他作为资源服务进行集成
6.测试服务 作为resource server 进行认证测试
对resource server 集成比较简单,只需要继承ResourceServerConfigurerAdapter,然后开启
@EnableResourceServer 即可 ,然后我们创建一个controller ,对该controller url进行校验
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
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
提示很明显,需要提供访问认证
我们现在获取一下access_token
{
"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
这次正常可以访问资源的url了 ,注意access_token前要加bearer
篇幅太长,本文到此就结束了,我们现在都是在内存环境集成的,真实开发肯定不是这样的,我们一步步来, 下篇我们将内存式变为从redis 和数据库获取数据,达到真实框架能力