Immediately above Build spring cloud alibaba microservice large application framework (II) (Mini cloud) creation project from 0 to 1 and build source code startup version nacos registry Today, let's talk in detail about how to build a certification center, that is, auth2 in the figure below 0 authentication service
There are many aspects involved today. I will also talk about some internal principles and codes, so it is divided into upper, middle and lower parts
The whole film is mainly based on the following process. It is also a process from scratch and from coarse to fine. It is close to everyone's development process as much as possible. What this paper introduces is not the final version. There will be some articles on refactoring code later. In the early stage, it will not be done step by step. It will directly paste the perfect code and become perfect step by step. I think the latter is more helpful to you, The source code will be exposed to github later
OK, let's introduce the overall article process first
##1. Create authentication center service ##2. Integrate the authentication center service into the spring cloud nacos registry ##3. Select oauth2 authentication mode, separate authentication server and resource server, and design sinking resource side authentication mode ##4. Build oauth2 client authentication according to the official memory authentication demo of spring ##5. Add the test service module and integrate it into spring cloud nacos ##6. The test service performs authentication test as a resource server ##7. Bring the configuration file parameters into the nacos configuration center for management ##8. Change the in memory authentication to the actual redis and clientdetail, and the userdetail is obtained from the database ##9. Change demo permission authentication to dynamically verify permissions according to the current login user role ##10. Extract the common part between the authentication server and the resource server and change it to common module ##11. Apply the common module to reconstruct the code and verify the authentication again
1. Create authentication center service
We will create a new module in the mini cloud directory, named authentication center, that is, the authentication center, which is specially used to authenticate and obtain access_ token ,reflush_ token ,check_ After creating the module, we integrate the service into the spring cloud nacos system
2. Integrate the authentication center service into the spring cloud nacos registry
Where relevant changes are required, there are the following documents, and the code is given
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> <!--Registry client--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--Configuration center client--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--Security module --> <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 modular--> <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>
In fact, spring cloud integration only needs
In addition, the previous Mini cloud root POM There are some changes in XML, some dependency management is added, and all of them are posted directly
<?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> <!-- Management dependent version number,Subprojects are not dependent by default --> <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> <!--Stable version, replace spring security bom built-in--> <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> <!-- there ID Be sure to maven setting File exists in server Lower 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> <!-- Environment ID, corresponding to the name of the configuration file --> <profiles.active>dev</profiles.active> </properties> <activation> <!-- Default environment --> <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>
The application name of the registration center has been changed and unified, from nacos to MiniCloudRegisterApplication
OK, test whether spring cloud nacos is integrated. Start the nacos registry first, and then the authentication center
Then visit http://localhost:8848/nacos/ Console
It is found that the authentication service just built and integrated into nacos
3. Select oauth2 authentication mode, separate authentication server and resource server, and design sinking resource side authentication mode
This involves some theoretical content. I drew two diagrams to describe what is authentication service, what is resource service, and what is their relationship. It is easier to understand
Certification services and resource services
The authentication service is associated with the resource service
To sum up in Vernacular:
Authentication service: mainly our authentication center. When all clients access the resource service, the resource service will internally access the authentication service to verify whether they have the right
Resource service: it is the accessed interface. If chivalry goes to the web, it can be said to be the url of our controller
For more information, visit spring auth2 0 official website and the demo provided by the official website can be run directly
auth2.0 official website introduction: https://projects.spring.io/spring-security-oauth/docs/oauth2.html
auth2.0 supports the following authentication modes by default by accessing the grant parameter_ Type discrimination
If you are interested, you can understand it. Let's briefly explain it here
Authorization code: authorization code mode. It is relatively safe, but it can only be used in web projects. A page url is required
client_credentials: the client mode is mainly used to authenticate an app or a service. For example, wechat platform for an application and Alibaba cloud oss for an application. It is not suitable for our common users to log in to the manufacturer through an account and password
Password: the user name and password mode is the commonly used scenario for users of this site to log in through user name and password. This paper mainly selects this mode. Later, we will talk about how to customize the authorization mode to support their own authorization, which is not within the scope of this paper
Although we choose the password mode, we still need to support client authentication, because our certification center may need to support the access of other external services in the future, so we still need to have a clientId for each service and the resource permission identification of the common end
4. Build oauth2 client authentication according to the official memory authentication demo of spring
When we develop any function, we usually want to use the simplest demo to complete the minimum environmental protection certificate and run first. We also do the same. We can directly change the demo on the official website to ensure that we run first
auth2.0 official website demo address: GitHub - jgrandja/spring-security-oauth-2-4-migrate
Authentication services generally need to do two things
1. Inherit the @ EnableAuthorizationServer configureradapter and start @ EnableAuthorizationServer
2. Inherit WebSecurityConfigurerAdapter and start @ EnableWebSecurity
1 is to add your own server-side custom bean s, such as clientservice userdetailservice
2 is to inject interceptors required by the web service itself or URLs to be intercepted
Don't gossip. There is little code in itself, and it runs in memory mode. I directly the code, and I also made detailed comments on the code
We just need to add two files
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 :For example, the memory mode is directly injected into one client side of the simulation * withClient :clientId * secret: clientId Corresponding password, remember spring 5 0 should be preceded by {encryption} ciphertext * authorizedGrantTypes: Which authorization modes are accepted? Parameter grant_type discrimination * authorities: What permissions do you have, usually at the api level, are basically useless * scopes: Read / write level * */ @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: Set auth2 0 itself has open access rights * Here for / oauth/check_token opens the form submission permission */ @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients(); } /** * @desc: It mainly injects custom service s into endpoints (url path of the framework itself) * The default userDetailsService and authenticationManager are injected into the, */ @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:url interception settings for this web service * All permissions of / oauth / * * are open here because it is the path of the framework * */ @Override public void configure(HttpSecurity http) throws Exception { http .requestMatchers().anyRequest() .and() .authorizeRequests() .antMatchers("/oauth/**").permitAll(); } /** * @desc:Inject the default AuthenticationManager bean */ @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } /** * @desc:Inject the default UserDetailsService bean and add two test users * username: user name * password: Password, also note the {encryption method} ciphertext * roles: Multiple roles can be implemented * */ @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:Inject PasswordEncoder encryptor * PasswordEncoderFactories.createDelegatingPasswordEncoder() The default is bcrypt encryption * */ @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } }
After adding the code, restart the authentication center service to verify it
I use user1. Remember that both clientId and password correspond,
ok, you can see that you have returned to access normally_ Token, and reflush_token, start the next step
5. Add the test service module and integrate it into spring cloud nacos
For convenience, I create a separate test module to place all the services related to the test service. In order to test the overall business of micro services in the future, I also include the test service as a business side service into spring cloud nacos
Well, let's create a test business side for integration testing as a resource service. The integration into spring cloud nacos is the same as the above certification center integration. I won't say more
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 modular--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Registry client--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--Configuration center client--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--Security module --> <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>
Then start them all to see if they are all integrated into nacos
Enter the nacos console to view http://localhost:8848/nacos/
ok, no problem. Start integrating it as a resource service
6. The test service performs authentication test as a resource server
The resource server integration is relatively simple. You only need to inherit the ResourceServerConfigurerAdapter and start it
@Enable resource server, and then we create a controller to verify the 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: Set the url that needs to be intercepted or opened * The url of the / oauth / * * framework itself is open here * Certification is required for / test / * * related * */ @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
Note: token info URI: This is the address of our certification center
We restart the test service and then start the test. First, we directly access our test controller url
http://localhost:8900/test/hello
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
It is obvious that access authentication needs to be provided
Let's get access now_ token
{
"access_token": "6ee98a60-19c6-4843-9f77-954024bc2d9b",
"token_type": "bearer",
"refresh_token": "b6bf88c0-1128-4742-af8a-74bc513b7d9b",
"expires_in": 41459,
"scope": "read"
}
We got access_token, and then access http://localhost:8900/test/hello
The url of the resource can be accessed normally this time. Pay attention to access_ Bear should be added before token
The length is too long. This article ends here. We are now integrated in the memory environment, which is certainly not the case for real development. Let's take it step by step. In the next article, we will change the memory mode to obtain data from redis and database to achieve the real framework capability