原因SSO-springcloud-alibaba 搜了一些都不完整现在记录一下自己整理的完整源码分享出来解决1.项目结构一个项目alibaba_sso)2个模块(moduleauth-server/module moduleresource-server/module)。2.直接放源码项目pom(alibaba_sso.pom)?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent groupIdcom.dp/groupId artifactIdalibaba_sso/artifactId version1.0.0/version namealibaba_sso/name descriptionalibaba_sso/description packagingpom/packaging modules moduleauth-server/module moduleresource-server/module /modules properties java.version17/java.version spring-cloud.version2021.0.9/spring-cloud.version spring-cloud-alibaba.version2021.0.6.0/spring-cloud-alibaba.version spring-security-oauth2.version2.5.12/spring-security-oauth2.version jjwt.version0.11.5/jjwt.version /properties dependencyManagement dependencies !-- Spring Cloud -- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version${spring-cloud.version}/version typepom/type scopeimport/scope /dependency !-- Spring Cloud Alibaba -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version${spring-cloud-alibaba.version}/version typepom/type scopeimport/scope /dependency !-- Spring Security OAuth2 -- dependency groupIdorg.springframework.security.oauth.boot/groupId artifactIdspring-security-oauth2-autoconfigure/artifactId version${spring-security-oauth2.version}/version /dependency !-- JJWT -- dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version${jjwt.version}/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version${jjwt.version}/version scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId version${jjwt.version}/version scoperuntime/scope /dependency /dependencies /dependencyManagement build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /projectauth_server:pom?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdcom.dp/groupId artifactIdalibaba_sso/artifactId version1.0.0/version /parent artifactIdauth-server/artifactId nameauth-server/name descriptionauth-server/description properties java.version17/java.version /properties dependencies !-- Spring Boot Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Spring Security -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency !-- Spring Security OAuth2 -- dependency groupIdorg.springframework.security.oauth.boot/groupId artifactIdspring-security-oauth2-autoconfigure/artifactId /dependency !-- JJWT -- dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId scoperuntime/scope /dependency !-- Nacos Discovery -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /projectAuthServerApplication.javapackage com.dp.authserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; SpringBootApplication EnableDiscoveryClient // 注册到 Nacos public class AuthServerApplication { public static void main(String[] args) { SpringApplication.run(AuthServerApplication.class, args); } }AuthServerConfig.javapackage com.dp.authserver.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.authentication.builders.AuthenticationManagerBuilder; 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.password.PasswordEncoder; 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 org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; import org.springframework.security.provisioning.InMemoryUserDetailsManager; /** * 认证服务器配置 * * 认证方式OAuth2 密码模式Password Grant * * 流程说明 * 1. 客户端使用用户名/密码向 /oauth/token 请求 token * 2. 认证服务器验证用户名密码生成 JWT Token 返回 * 3. 客户端携带 Token 访问资源服务器 * */ Configuration EnableWebSecurity EnableAuthorizationServer // 启用 OAuth2 认证服务器 public class AuthServerConfig { /** * 密码编码器 * 使用 BCrypt 加密存储时自动加盐 */ Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } /** * 用户认证管理器 * 负责验证用户名和密码 */ Bean public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { return http.getSharedObject(AuthenticationManagerBuilder.class) .userDetailsService(userDetailsService()) .passwordEncoder(passwordEncoder()) .and() .build(); } /** * 用户详情服务 * 定义测试用户admin/123456 * 密码使用 BCrypt 加密 */ Bean public UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager new InMemoryUserDetailsManager(); // 密码: 123456 的 BCrypt 加密结果 manager.createUser(User.withUsername(admin) .password($2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iKTVKIUi) .roles(USER, ADMIN) .build()); manager.createUser(User.withUsername(user) .password($2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iKTVKIUi) .roles(USER) .build()); return manager; } /** * JWT Token 存储 * 使用 JWT 格式存储 Token无需 Redis */ Bean public TokenStore tokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } /** * JWT Token 转换器 * 配置签名密钥用于生成和验证 JWT */ Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter new JwtAccessTokenConverter(); // 签名密钥生产环境请使用更强的密钥 converter.setSigningKey(sso-secret-key-2024); return converter; } /** * Spring Security 配置 * 允许所有用户访问 /oauth/token 端点 */ Configuration public static class SecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers(/oauth/token, /oauth/authorize).permitAll() .anyRequest().authenticated() .and() .csrf().disable() .formLogin().disable() .httpBasic(); } } /** * OAuth2 授权服务器配置 * 定义客户端信息和 Token 端点 */ Configuration public static class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { private final AuthenticationManager authenticationManager; private final TokenStore tokenStore; private final JwtAccessTokenConverter jwtAccessTokenConverter; public AuthorizationServerConfig( AuthenticationManager authenticationManager, TokenStore tokenStore, JwtAccessTokenConverter jwtAccessTokenConverter) { this.authenticationManager authenticationManager; this.tokenStore tokenStore; this.jwtAccessTokenConverter jwtAccessTokenConverter; } /** * 配置客户端信息 * 定义哪些应用可以访问认证服务器 */ Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 使用 BCrypt 编码客户端密码 PasswordEncoder encoder new BCryptPasswordEncoder(); String encodedClientSecret encoder.encode(gateway-secret); clients.inMemory() .withClient(gateway-client) .secret(encodedClientSecret) // 使用 BCrypt 编码的密码 .authorizedGrantTypes( password, refresh_token ) .scopes(all, read, write) .accessTokenValiditySeconds(3600) .refreshTokenValiditySeconds(86400); } /** * 配置 Token 端点 * 设置认证管理器和 Token 存储 */ Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints .authenticationManager(authenticationManager) // 密码模式需要 .tokenStore(tokenStore) // Token 存储 .accessTokenConverter(jwtAccessTokenConverter); // JWT 转换器 } /** * 配置 Token 端点的安全策略 * 允许表单认证和客户端认证 */ Override public void configure(AuthorizationServerSecurityConfigurer security) { security .tokenKeyAccess(permitAll()) // 允许所有访问 /oauth/token_key .checkTokenAccess(isAuthenticated()) // 检查 Token 需要认证 .allowFormAuthenticationForClients(); // 允许表单认证 } } }applicaiton.ymlserver: port: 9001 spring: application: name: auth-server cloud: nacos: discovery: server-addr: localhost:8848 namespace: public logging: level: org.springframework.security: DEBUG org.springframework.security.oauth2: DEBUGresource-server:pom.xml?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdcom.dp/groupId artifactIdalibaba_sso/artifactId version1.0.0/version /parent artifactIdresource-server/artifactId nameresource-server/name descriptionresource-server/description properties java.version17/java.version /properties dependencies !-- Spring Boot Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Spring Security OAuth2 Resource Server -- dependency groupIdorg.springframework.security.oauth.boot/groupId artifactIdspring-security-oauth2-autoconfigure/artifactId /dependency !-- JJWT -- dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId scoperuntime/scope /dependency !-- Nacos Discovery -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /projectResourceServerApplication.javapackage com.dp.resourceserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; SpringBootApplication EnableDiscoveryClient public class ResourceServerApplication { public static void main(String[] args) { SpringApplication.run(ResourceServerApplication.class, args); } }ResourceServerConfig.javapackage com.dp.resourceserver.config; import org.springframework.context.annotation.Bean; 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; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; /** * 资源服务器配置 * * 验证流程 * 1. 使用与认证服务器相同的 JWT 签名密钥 * 2. 验证 Token 签名和有效期 * * 关键setSigningKey() 用于设置签名密钥验证时使用 * */ Configuration EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { /** * JWT 签名密钥必须与认证服务器完全一致 */ private static final String JWT_SIGNING_KEY sso-secret-key-2024; /** * Token 存储 - 使用 JWT 格式 */ Bean public TokenStore tokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } /** * JWT Token 转换器 - 配置签名密钥 * * 注意使用 setSigningKey() 而不是 setVerificationKey() * 在 Spring Security OAuth2 中JwtAccessTokenConverter 使用 setSigningKey() 同时处理签名和验证 */ Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter new JwtAccessTokenConverter(); // 设置签名密钥必须与认证服务器相同 converter.setSigningKey(JWT_SIGNING_KEY); return converter; } /** * Token 服务 */ Bean public DefaultTokenServices tokenServices() { DefaultTokenServices services new DefaultTokenServices(); services.setTokenStore(tokenStore()); return services; } /** * 配置资源ID */ Override public void configure(ResourceServerSecurityConfigurer resources) { resources.resourceId(resource-server) .stateless(true) .tokenServices(tokenServices()); } /** * 配置接口访问权限 */ Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // 公开接口 .antMatchers(/api/public/**).permitAll() // 用户接口需要认证 .antMatchers(/api/user/**).authenticated() // 管理员接口需要 ADMIN 角色 .antMatchers(/api/admin/**).hasRole(ADMIN) .anyRequest().authenticated() .and() .csrf().disable(); } }UserController.javapackage com.dp.resourceserver.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.security.Principal; import java.util.HashMap; import java.util.Map; RestController RequestMapping(/api) public class UserController { /** * 公开接口 - 不需要 Token */ GetMapping(/public/health) public MapString, Object health() { MapString, Object result new HashMap(); result.put(status, UP); result.put(service, resource-server); result.put(message, Service is running); return result; } /** * 用户信息接口 - 需要 Token * 通过 Principal 获取当前登录用户 */ GetMapping(/user/info) public MapString, Object getUserInfo(Principal principal) { Authentication authentication SecurityContextHolder.getContext().getAuthentication(); MapString, Object result new HashMap(); result.put(username, principal.getName()); result.put(authenticated, authentication.isAuthenticated()); result.put(authorities, authentication.getAuthorities()); result.put(service, resource-server); return result; } /** * 管理员接口 - 需要 ADMIN 角色 */ GetMapping(/admin/dashboard) public MapString, Object adminDashboard() { MapString, Object result new HashMap(); result.put(data, Admin Dashboard Data); result.put(service, resource-server); return result; } }application.ymlserver: port: 9002 spring: application: name: resource-server cloud: nacos: discovery: server-addr: localhost:8848 namespace: public # JWT 签名密钥必须与认证服务器一致 jwt: secret: sso-secret-key-2024 logging: level: org.springframework.security: DEBUG3.启动3.1 启动 nacos我的版本是3.0.23.2 启动 auth-server3.3 启动 resource-server4.测试(用的postman)4.1 获取token:http://localhost:9001/oauth/tokenpostheader:Authorization:Basic Z2F0ZXdheS1jbGllbnQ6Z2F0ZXdheS1zZWNyZXQbody:grant_type:passwordusername:adminpassword:123456scope:all返回{access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NzQ4Njg0MzEsInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiJsVGNVblBSaVg4WENqX3Vva2hXeERFZHVlcXMiLCJjbGllbnRfaWQiOiJnYXRld2F5LWNsaWVudCIsInNjb3BlIjpbImFsbCJdfQ.cQ_jzo7nwuTyinx5Xt4qQt2ZCcKo5_K0s-JxPnti3G8,token_type: bearer,refresh_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiJsVGNVblBSaVg4WENqX3Vva2hXeERFZHVlcXMiLCJleHAiOjE3NzQ5NTEyMzEsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiXSwianRpIjoiNVpMVlRSTmFwcVEtX1ZzRnlNZkp0Uk90NnlVIiwiY2xpZW50X2lkIjoiZ2F0ZXdheS1jbGllbnQifQ.x3_Mb0gYR8YDWlBc8hE2oEKzECx6ed7_YJc8v8sSgKE,expires_in: 3599,scope: all,jti: lTcUnPRiX8XCj_uokhWxDEdueqs}4.2 测试数据http://localhost:9002/api/user/infoheader:Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NzQ4NjQ0NDAsInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiIwbVJDVVkzWjNuTTFiamZfSmxIaVN2ek1JWDQiLCJjbGllbnRfaWQiOiJnYXRld2F5LWNsaWVudCIsInNjb3BlIjpbImFsbCJdfQ.tlveU1Br_PsPXfZIKHYB6pXlCpkEj9cS7gc93KUGQXU返回{authenticated: true,service: resource-server,authorities: [{authority: ROLE_ADMIN},{authority: ROLE_USER}],username: admin}4.3 http://localhost:9002/api/admin/dashboardheader 一样权限不一样的测试4.4 不用执行备份收藏的postman的测试方式原理等大家实现后看注释就可以先跑通。代码放deepseek也可以