
<localRepository>D:\Tools\maven_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 Files\Java\jdk1.8.0_111\bin\java.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:\Users\back_\AppData\Local\JetBrains\IntelliJIdea2020.1\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\ProjectWork\reims\nacos\target\classes;D:\Tools\maven_repo\org\springframework\boot\spring-boot-starter-web\2.2.6.RELEASE\spring-boot-starter-web-2.2.6.RELEASE.jar;D:\Tools\maven_repo\org\springframework\boot\spring-boot-starter\2.2.6.RELEASE\spring-boot-starter-2.2.6.RELEASE.jar;D:\Tools\maven_repo\org\springframework\boot\spring-boot\2.2.6.RELEASE\spring-boot-2.2.6.RELEASE.jar;D:\Tools\maven_repo\org\springframework\boot\spring-boot-autoconfigure\2.2.6.RELEASE\spring-boot-autoconfigure-2.2.6.RELEASE.jar;D:\Tools\maven_repo\org\springframework\boot\spring-boot-starter-logging\2.2.6.RELEASE\spring-boot-starter-logging-2.2.6.RELEASE.jar;D:\Tools\maven_repo\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\Tools\maven_repo\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\Tools\maven_repo\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;D:\Tools\maven_repo\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;D:\Tools\maven_repo\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\Tools\maven_repo\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\Tools\maven_repo\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;D:\Tools\maven_repo\org\springframework\boot\spring-boot-starter-json\2.2.6.RELEASE\spring-boot-starter-json-2.2.6.RELEASE.jar;D:\Tools\maven_repo\com\fasterxml\jackson\core\jackson-databind\2.10.3\jackson-databind-2.10.3.jar;D:\Tools\maven_repo\com\fasterxml\jackson\core\jackson-annotations\2.10.3\jackson-annotations-2.10.3.jar;D:\Tools\maven_repo\com\fasterxml\jackson\core\jackson-core\2.10.3\jackson-core-2.10.3.jar;D:\Tools\maven_repo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.3\jackson-datatype-jdk8-2.10.3.jar;D:\Tools\maven_repo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.3\jackson-datatype-jsr310-2.10.3.jar;D:\Tools\maven_repo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.3\jackson-module-parameter-names-2.10.3.jar;D:\Tools\maven_repo\org\springframework\boot\spring-boot-starter-tomcat\2.2.6.RELEASE\spring-boot-starter-tomcat-2.2.6.RELEASE.jar;D:\Tools\maven_repo\org\apache\tomcat\embed\tomcat-embed-core\9.0.33\tomcat-embed-core-9.0.33.jar;D:\Tools\maven_repo\org\apache\tomcat\embed\tomcat-embed-el\9.0.33\tomcat-embed-el-9.0.33.jar;D:\Tools\maven_repo\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.33\tomcat-embed-websocket-9.0.33.jar;D:\Tools\maven_repo\org\springframework\boot\spring-boot-starter-validation\2.2.6.RELEASE\spring-boot-starter-validation-2.2.6.RELEASE.jar;D:\Tools\maven_repo\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\Tools\maven_repo\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;D:\Tools\maven_repo\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;D:\Tools\maven_repo\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\Tools\maven_repo\org\springframework\spring-web\5.2.5.RELEASE\spring-web-5.2.5.RELEASE.jar;D:\Tools\maven_repo\org\springframework\spring-beans\5.2.5.RELEASE\spring-beans-5.2.5.RELEASE.jar;D:\Tools\maven_repo\org\springframework\spring-webmvc\5.2.5.RELEASE\spring-webmvc-5.2.5.RELEASE.jar;D:\Tools\maven_repo\org\springframework\spring-aop\5.2.5.RELEASE\spring-aop-5.2.5.RELEASE.jar;D:\Tools\maven_repo\org\springframework\spring-context\5.2.5.RELEASE\spring-context-5.2.5.RELEASE.jar;D:\Tools\maven_repo\org\springframework\spring-expression\5.2.5.RELEASE\spring-expression-5.2.5.RELEASE.jar;D:\Tools\maven_repo\mysql\mysql-connector-java\8.0.19\mysql-connector-java-8.0.19.jar;D:\Tools\maven_repo\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\Tools\maven_repo\org\springframework\spring-core\5.2.5.RELEASE\spring-core-5.2.5.RELEASE.jar;D:\Tools\maven_repo\org\springframework\spring-jcl\5.2.5.RELEASE\spring-jcl-5.2.5.RELEASE.jar;D:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\lib\idea_rt.jar" com.reims.main.nacos.NacosApplicationConnected 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\reims\nacos\target\classes started by wei in D:\ProjectWork\reims\nacos)2020-05-01 12:22:08.227 INFO 2316 --- [ main] com.reims.main.nacos.NacosApplication : No active profile set, falling back to default profiles: default2020-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 WebApplicationContext2020-05-01 12:22:08.997 INFO 2316 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 729 ms2020-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包引用:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>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 中添加端口和访问域:
# springserver.servlet.context-path=/nacosserver.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.2020-05-01 23:06:43.745 ERROR 18756 --- [ main] o.s.boot.SpringApplication : Application run failedorg.springframework.beans.factory.UnsatisfiedDependencyException: 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 omittedCaused 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 omittedCaused 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 omittedDisconnected from the target VM, address: '127.0.0.1:55865', transport: 'socket'Process finished with exit code 1
useAddressServer=true



登录流程详探
@PostMapping("/login")public Object login(@RequestParam String username, @RequestParam 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 认证对象,实现类为 UsernamePasswordAuthenticationTokenUsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);RestResult<String> rr = new RestResult<String>();try {//通过 AuthenticationManager(默认实现为ProviderManager)的authenticate方法验证 Authentication 对象Authentication authentication = authenticationManager.authenticate(authenticationToken);//将 Authentication 绑定到 SecurityContextSecurityContextHolder.getContext().setAuthentication(authentication);//生成TokenString 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=nacosnacos.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
@Overridepublic 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的authenticatereturn 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 usernameString username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED": authentication.getName();boolean cacheWasUsed = true;//这里从userCache中获取继承了UserDetails的servicesUserDetails 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*/@Servicepublic class NacosUserDetailsServiceImpl implements UserDetailsService {private Map<String, User> userMap = new ConcurrentHashMap<>();@Autowiredprivate UserPersistService userPersistService;@Autowiredprivate AuthConfigs authConfigs;@Scheduled(initialDelay = 5000, fixedDelay = 15000)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);}}@Overridepublic 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 的验证过程和原理,不过这些不在本篇中详细讲述了,更多问题留待以后具体分析。





