第四篇:Nacos Server 详探
Posted 重塑之路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第四篇:Nacos Server 详探相关的知识,希望对你有一定的参考价值。
<localRepository>D:Toolsmaven_repo</localRepository>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
创建完毕,项目结构:
启动NacosApplication.java
"C:Program FilesJavajdk1.8.0_111injava.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:57519,suspend=y,server=n -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:C:Usersack_AppDataLocalJetBrainsIntelliJIdea2020.1captureAgentdebugger-agent.jar -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_111jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_111jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_111jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_111jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_111jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_111jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_111jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_111jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_111jrelibext ashorn.jar;C:Program FilesJavajdk1.8.0_111jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_111jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_111jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_111jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_111jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_111jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_111jrelibjce.jar;C:Program FilesJavajdk1.8.0_111jrelibjfr.jar;C:Program FilesJavajdk1.8.0_111jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_111jrelibjsse.jar;C:Program FilesJavajdk1.8.0_111jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_111jrelibplugin.jar;C:Program FilesJavajdk1.8.0_111jrelib esources.jar;C:Program FilesJavajdk1.8.0_111jrelib t.jar;D:ProjectWork eims acos argetclasses;D:Toolsmaven_repoorgspringframeworkootspring-boot-starter-web2.2.6.RELEASEspring-boot-starter-web-2.2.6.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkootspring-boot-starter2.2.6.RELEASEspring-boot-starter-2.2.6.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkootspring-boot2.2.6.RELEASEspring-boot-2.2.6.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkootspring-boot-autoconfigure2.2.6.RELEASEspring-boot-autoconfigure-2.2.6.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkootspring-boot-starter-logging2.2.6.RELEASEspring-boot-starter-logging-2.2.6.RELEASE.jar;D:Toolsmaven_repochqoslogbacklogback-classic1.2.3logback-classic-1.2.3.jar;D:Toolsmaven_repochqoslogbacklogback-core1.2.3logback-core-1.2.3.jar;D:Toolsmaven_repoorgapachelogginglog4jlog4j-to-slf4j2.12.1log4j-to-slf4j-2.12.1.jar;D:Toolsmaven_repoorgapachelogginglog4jlog4j-api2.12.1log4j-api-2.12.1.jar;D:Toolsmaven_repoorgslf4jjul-to-slf4j1.7.30jul-to-slf4j-1.7.30.jar;D:Toolsmaven_repojakartaannotationjakarta.annotation-api1.3.5jakarta.annotation-api-1.3.5.jar;D:Toolsmaven_repoorgyamlsnakeyaml1.25snakeyaml-1.25.jar;D:Toolsmaven_repoorgspringframeworkootspring-boot-starter-json2.2.6.RELEASEspring-boot-starter-json-2.2.6.RELEASE.jar;D:Toolsmaven_repocomfasterxmljacksoncorejackson-databind2.10.3jackson-databind-2.10.3.jar;D:Toolsmaven_repocomfasterxmljacksoncorejackson-annotations2.10.3jackson-annotations-2.10.3.jar;D:Toolsmaven_repocomfasterxmljacksoncorejackson-core2.10.3jackson-core-2.10.3.jar;D:Toolsmaven_repocomfasterxmljacksondatatypejackson-datatype-jdk82.10.3jackson-datatype-jdk8-2.10.3.jar;D:Toolsmaven_repocomfasterxmljacksondatatypejackson-datatype-jsr3102.10.3jackson-datatype-jsr310-2.10.3.jar;D:Toolsmaven_repocomfasterxmljacksonmodulejackson-module-parameter-names2.10.3jackson-module-parameter-names-2.10.3.jar;D:Toolsmaven_repoorgspringframeworkootspring-boot-starter-tomcat2.2.6.RELEASEspring-boot-starter-tomcat-2.2.6.RELEASE.jar;D:Toolsmaven_repoorgapache omcatembed omcat-embed-core9.0.33 omcat-embed-core-9.0.33.jar;D:Toolsmaven_repoorgapache omcatembed omcat-embed-el9.0.33 omcat-embed-el-9.0.33.jar;D:Toolsmaven_repoorgapache omcatembed omcat-embed-websocket9.0.33 omcat-embed-websocket-9.0.33.jar;D:Toolsmaven_repoorgspringframeworkootspring-boot-starter-validation2.2.6.RELEASEspring-boot-starter-validation-2.2.6.RELEASE.jar;D:Toolsmaven_repojakartavalidationjakarta.validation-api2.0.2jakarta.validation-api-2.0.2.jar;D:Toolsmaven_repoorghibernatevalidatorhibernate-validator6.0.18.Finalhibernate-validator-6.0.18.Final.jar;D:Toolsmaven_repoorgjbossloggingjboss-logging3.4.1.Finaljboss-logging-3.4.1.Final.jar;D:Toolsmaven_repocomfasterxmlclassmate1.5.1classmate-1.5.1.jar;D:Toolsmaven_repoorgspringframeworkspring-web5.2.5.RELEASEspring-web-5.2.5.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkspring-beans5.2.5.RELEASEspring-beans-5.2.5.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkspring-webmvc5.2.5.RELEASEspring-webmvc-5.2.5.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkspring-aop5.2.5.RELEASEspring-aop-5.2.5.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkspring-context5.2.5.RELEASEspring-context-5.2.5.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkspring-expression5.2.5.RELEASEspring-expression-5.2.5.RELEASE.jar;D:Toolsmaven_repomysqlmysql-connector-java8.0.19mysql-connector-java-8.0.19.jar;D:Toolsmaven_repoorgslf4jslf4j-api1.7.30slf4j-api-1.7.30.jar;D:Toolsmaven_repoorgspringframeworkspring-core5.2.5.RELEASEspring-core-5.2.5.RELEASE.jar;D:Toolsmaven_repoorgspringframeworkspring-jcl5.2.5.RELEASEspring-jcl-5.2.5.RELEASE.jar;D:Program FilesJetBrainsIntelliJ IDEA 2020.1.1libidea_rt.jar" com.reims.main.nacos.NacosApplication
Connected to the target VM, address: '127.0.0.1:57519', transport: 'socket'
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _
( ( )\___ | '_ | '_| | '_ / _` |
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.6.RELEASE)
2020-05-01 12:22:08.223 INFO 2316 --- [ main] com.reims.main.nacos.NacosApplication : Starting NacosApplication on DESKTOP-MBI0KTI with PID 2316 (D:ProjectWork eims acos argetclasses started by wei in D:ProjectWork eims acos)
2020-05-01 12:22:08.227 INFO 2316 --- [ main] com.reims.main.nacos.NacosApplication : No active profile set, falling back to default profiles: default
2020-05-01 12:22:08.933 INFO 2316 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-05-01 12:22:08.940 INFO 2316 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-05-01 12:22:08.940 INFO 2316 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33]
2020-05-01 12:22:08.997 INFO 2316 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-05-01 12:22:08.997 INFO 2316 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 729 ms
2020-05-01 12:22:09.116 INFO 2316 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-05-01 12:22:09.241 INFO 2316 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-01 12:22:09.243 INFO 2316 --- [ main] com.reims.main.nacos.NacosApplication : Started NacosApplication in 1.356 seconds (JVM running for 2.355)
添加nacos 相关jar包引用:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.reims.main</groupId>
<artifactId>nacos</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>nacos</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<nacos.version>1.2.1</nacos.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos Server 相关配置 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-config</artifactId>
<version>${nacos.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-core</artifactId>
<version>${nacos.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-naming</artifactId>
<version>${nacos.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<!-- Nacos Server END -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
前端我们先直接复用,copy源码中static 目录 到resources 目录下
此时启动项目即可访问 http://localhost:8080,但是无法登录:
在application.properties 中添加端口和访问域:
# spring
server.servlet.context-path=/nacos
server.port=9000
实现功能
@SpringBootApplication(scanBasePackages=("com.reims.main,com.alibaba.nacos"))
启动参数中添加单机启动:
-Dnacos.standalone=true
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
23:06:43.745 ERROR 18756 --- [ main] o.s.boot.SpringApplication : Application run failed
Error creating bean with name 'configController' defined in URL [jar:file:/D:/Tools/maven_repo/com/alibaba/nacos/nacos-config/1.2.1/nacos-config-1.2.1.jar!/com/alibaba/nacos/config/server/controller/ConfigController.class]: Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'configSubService' defined in URL [jar:file:/D:/Tools/maven_repo/com/alibaba/nacos/nacos-config/1.2.1/nacos-config-1.2.1.jar!/com/alibaba/nacos/config/server/service/ConfigSubService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverListService': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'useAddressServer' in value "${useAddressServer}" :
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:228)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1358)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:882)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at com.reims.main.nacos.NacosApplication.main(NacosApplication.java:11)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'configSubService' defined in URL [jar:file:/D:/Tools/maven_repo/com/alibaba/nacos/nacos-config/1.2.1/nacos-config-1.2.1.jar!/com/alibaba/nacos/config/server/service/ConfigSubService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverListService': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'useAddressServer' in value "${useAddressServer}"
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:228)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1358)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1290)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1210)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
19 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverListService': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'useAddressServer' in value "${useAddressServer}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:405)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1290)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1210)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
33 common frames omitted
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'useAddressServer' in value "${useAddressServer}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:178)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:236)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:909)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1231)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1210)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
45 common frames omitted
Disconnected from the target VM, address: '127.0.0.1:55865', transport: 'socket'
Process finished with exit code 1
useAddressServer=true
登录流程详探
"/login") (
public Object login( String username, String password,
HttpServletResponse response, HttpServletRequest request) throws AccessException {
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
NacosUser user = (NacosUser) authManager.login(request);
response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER,
NacosAuthConfig.TOKEN_PREFIX + user.getToken());
JSONObject result = new JSONObject();
result.put(Constants.ACCESS_TOKEN, user.getToken());
result.put(Constants.TOKEN_TTL, authConfigs.getTokenValidityInSeconds());
result.put(Constants.GLOBAL_ADMIN, user.isGlobalAdmin());
return result;
}
// 通过用户名和密码创建一个 Authentication 认证对象,实现类为 UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
RestResult<String> rr = new RestResult<String>();
try {
//通过 AuthenticationManager(默认实现为ProviderManager)的authenticate方法验证 Authentication 对象
Authentication authentication = authenticationManager.authenticate(authenticationToken);
//将 Authentication 绑定到 SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
//生成Token
String token = jwtTokenUtils.createToken(authentication);
//将Token写入到Http头部
response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, "Bearer " + token);
rr.setCode(200);
rr.setData("Bearer " + token);
return rr;
} catch (BadCredentialsException authentication) {
rr.setCode(401);
rr.setMessage("Login failed");
return rr;
}
}
nacos.core.auth.system.type=nacos
nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
目前发现的区别在于使用以上配置时,生成tocken时会使用这个key和userName进行计算生成Tocken:
/**
* Create token
*
* @param authentication auth info
* @return token
*/
public String createToken(Authentication authentication) {
return createToken(authentication.getName());
}
public String createToken(String userName) {
long now = (new Date()).getTime();
Date validity;
validity = new Date(now + authConfigs.getTokenValidityInSeconds() * 1000L);
Claims claims = Jwts.claims().setSubject(userName);
return Jwts.builder()
.setClaims(claims)
.setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, authConfigs.getSecretKey())
.compact();
}
未使用时,是直接生成的:
String token = jwtTokenUtils.createToken(authentication);
/**
* Create token
*
* @param authentication auth info
* @return token
*/
public String createToken(Authentication authentication) {
/**
* Current time
*/
long now = (new Date()).getTime();
/**
* Validity date
*/
Date validity;
validity = new Date(now + this.tokenValidityInMilliseconds);
/**
* create token
*/
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY, "")
.setExpiration(validity)
.signWith(secretKey, SignatureAlgorithm.HS256)
.compact();
}
举例:
使用nacos.core.auth.system.type使生成的tocken为:
不使用是生成tocken为:
可以看出,生成的方式明显是不一样的,第一种的更安全一些。
我们详细看下两种验证的方式:
第一种:
首先进入authManager.login 开始处理
通过resolveToken(req)来进行校验和生成Tocken
public User login(Object request) throws AccessException {
HttpServletRequest req = (HttpServletRequest) request;
String token = resolveToken(req);
if (StringUtils.isBlank(token)) {
throw new AccessException("user not found!");
}
try {
tokenManager.validateToken(token);
} catch (ExpiredJwtException e) {
throw new AccessException("token expired!");
} catch (Exception e) {
throw new AccessException("token invalid!");
}
Authentication authentication = tokenManager.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
String username = authentication.getName();
NacosUser user = new NacosUser();
user.setUserName(username);
user.setToken(token);
List<RoleInfo> roleInfoList = roleService.getRoles(username);
if (roleInfoList != null) {
for (RoleInfo roleInfo : roleInfoList) {
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
user.setGlobalAdmin(true);
break;
}
}
}
return user;
}
/**
* Get token from header
*/
private String resolveToken(HttpServletRequest request) throws AccessException {
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
return bearerToken.substring(7);
}
bearerToken = request.getParameter(Constants.ACCESS_TOKEN);
if (StringUtils.isBlank(bearerToken)) {
String userName = request.getParameter("username");
String password = request.getParameter("password");
bearerToken = resolveTokenFromUser(userName, password);
}
return bearerToken;
}
private String resolveTokenFromUser(String userName, String rawPassword) throws AccessException {
try {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName, rawPassword);
authenticationManager.authenticate(authenticationToken);
} catch (AuthenticationException e) {
throw new AccessException("unknown user!");
}
return tokenManager.createToken(userName);
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
if (delegate != null) {
//调用AbstractUserDetailsAuthenticationProvider的authenticate
return delegate.authenticate(authentication);
}
synchronized (delegateMonitor) {
if (delegate == null) {
delegate = this.delegateBuilder.getObject();
this.delegateBuilder = null;
}
}
return delegate.authenticate(authentication);
}
AbstractUserDetailsAuthenticationProvider的authenticate
然后从userCache中获取继承了UserDetails的services,调用其loadUserByUsername方法实现数据库查询
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
() -> messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.onlySupports",
"Only UsernamePasswordAuthenticationToken is supported"));
// Determine username
String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
: authentication.getName();
boolean cacheWasUsed = true;
//这里从userCache中获取继承了UserDetails的services
UserDetails user = this.userCache.getUserFromCache(username);
if (user == null) {
cacheWasUsed = false;
try {
//如果通过名称无法从this.userCache获取,这里进行处理,会进入DaoAuthenticationProvider的retrieveUser方法
user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);
}
catch (UsernameNotFoundException notFound) {
logger.debug("User '" + username + "' not found");
if (hideUserNotFoundExceptions) {
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
else {
throw notFound;
}
}
Assert.notNull(user,
"retrieveUser returned null - a violation of the interface contract");
}
try {
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken) authentication);
}
catch (AuthenticationException exception) {
if (cacheWasUsed) {
// There was a problem, so try again after checking
// we're using latest data (i.e. not from the cache)
cacheWasUsed = false;
user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken) authentication);
}
else {
throw exception;
}
}
postAuthenticationChecks.check(user);
if (!cacheWasUsed) {
this.userCache.putUserInCache(user);
}
Object principalToReturn = user;
if (forcePrincipalAsString) {
principalToReturn = user.getUsername();
}
return createSuccessAuthentication(principalToReturn, authentication, user);
}
DaoAuthenticationProvider的retrieveUser方法
final UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
prepareTimingAttackProtection();
try {
//通过这里来加载继承了UserDetails的services,然后调用loadUserByUsername来获取数据
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
catch (UsernameNotFoundException ex) {
mitigateAgainstTimingAttack(authentication);
throw ex;
}
catch (InternalAuthenticationServiceException ex) {
throw ex;
}
catch (Exception ex) {
throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
}
}
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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.reims.main.nacos.console.security.nacos.users;
import com.alibaba.nacos.config.server.auth.UserPersistService;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.User;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.core.utils.Loggers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Custem user service
*
* @author wfnuser
* @author nkorange
*/
public class NacosUserDetailsServiceImpl implements UserDetailsService {
private Map<String, User> userMap = new ConcurrentHashMap<>();
private UserPersistService userPersistService;
private AuthConfigs authConfigs;
5000, fixedDelay = 15000) (initialDelay =
private void reload() {
try {
Page<User> users = getUsersFromDatabase(1, Integer.MAX_VALUE);
if (users == null) {
return;
}
Map<String, User> map = new ConcurrentHashMap<>(16);
for (User user : users.getPageItems()) {
map.put(user.getUsername(), user);
}
userMap = map;
} catch (Exception e) {
Loggers.AUTH.warn("[LOAD-USERS] load failed", e);
}
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMap.get(username);
if (!authConfigs.isCachingEnabled()) {
user = userPersistService.findUserByUsername(username);
}
if (user == null) {
throw new UsernameNotFoundException(username);
}
return new NacosUserDetails(user);
}
public void updateUserPassword(String username, String password) {
userPersistService.updateUserPassword(username, password);
}
public Page<User> getUsersFromDatabase(int pageNo, int pageSize) {
return userPersistService.getUsers(pageNo, pageSize);
}
public User getUser(String username) {
User user = userMap.get(username);
if (!authConfigs.isCachingEnabled()) {
user = getUserFromDatabase(username);
}
return user;
}
public User getUserFromDatabase(String username) {
return userPersistService.findUserByUsername(username);
}
public void createUser(String username, String password) {
userPersistService.createUser(username, password);
}
public void deleteUser(String username) {
userPersistService.deleteUser(username);
}
}
到此,生成Tocken完成。在
NacosAuthManager
的login方法中,后续继续获取了角色相关的信息,有代码可知是直接差了数据库,就不在详细描述!
第二种:
第二种方式是直接根据用户名和密码,创建了一个UsernamePasswordAuthenticationToken,然后调用authenticate方法直接进入WebSecurityConfigurerAda的authenticate方法来进行验证,之后的用户名和密码调用数据库验证过程与第一种是一致的。
验证完成后,直接调用jwtTokenUtils.createToken(authentication)来生成Tocken
public String createToken(Authentication authentication) {
/**
* Current time
*/
long now = (new Date()).getTime();
/**
* Validity date
*/
Date validity;
validity = new Date(now + this.tokenValidityInMilliseconds);
/**
* create token
*/
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY, "")
.setExpiration(validity)
.signWith(secretKey, SignatureAlgorithm.HS256)
.compact();
}
至此,本次登录过程分析完毕,虽然更深的原理没有详细分析,比如Spring security 的验证过程和原理,不过这些不在本篇中详细讲述了,更多问题留待以后具体分析。
以上是关于第四篇:Nacos Server 详探的主要内容,如果未能解决你的问题,请参考以下文章
从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点)
Kubernetes第四篇:手把手打镜像并运行到k8s容器上(亲测可用)