Spring boot + Spring security OAuth2简介

本文介绍如何使用SpringBoot结合SpringsecurityOAuth2搭建安全认证系统,涵盖验证服务器、资源服务器配置,JWT支持等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring boot + Spring security OAuth2简介

之前的文章简单介绍了Spring MVC + Spring security OAuth2的简单配置方法,主要以XML进行配置。这一篇将使用Spring boot做一个更全面的说明,以Java和yml来进行配置~

虽然配置方式与之前相比有些不同,但是运作流程还是一样,依然是Filter chain进行各种顾虑和验证操作~

1、验证服务器(AuthorizationServer)

OAuth2验证服务器的主要功能包括:

1、验证用户的username和password;

2、验证客户端的client_id和secret;

3、为通过验证的用户或者客户端颁发code或者token;

4、验证客户端提供的token是否合法有效;

5、根据有效的token提供对应的用户或者客户端详细信息;

  • 添加依赖
plugins {
    id 'java'
}

group 'com.chenlei'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.3.RELEASE'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.0.3.RELEASE'
    compile group: 'org.springframework.security.oauth.boot', name: 'spring-security-oauth2-autoconfigure', version: '2.0.1.RELEASE'

    testCompile group: 'junit', name: 'junit', version: '4.12'
}

spring-security-oauth2-autoconfigure将为我们省去很多的配置事项

  • 启用AuthorizationServer
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

}

通过 @EnableAuthorizationServer 来启用AuthorizationServer的默认实现,以提供/oauth/token、/oauth/check_token、/oauth/authorize等endpoint

  • 配置User
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password(passwordEncoder.encode("admin")).authorities("IS_AUTHENTICATED_FULLY");
    }

}

在authorization_code模式下,通过Spring security来进行用户认证,SSO将通过此模式实现

  • 配置Client
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory().withClient("client-1")
            .secret(this.passwordEncoder.encode("client"))
            .authorizedGrantTypes("authorization_code")
            .scopes("read")
            .redirectUris("http://localhost:8081")
            .autoApprove(true)
            .and()
            .withClient("client-2")
            .secret(this.passwordEncoder.encode("client"))
            .authorizedGrantTypes("authorization_code")
            .scopes("read")
            .redirectUris("http://localhost:8082")
            .autoApprove(true)
            .and()
            .withClient("client-3")
            .secret(this.passwordEncoder.encode("client"))
            .authorizedGrantTypes("client_credentials")
            .scopes("rea.*")
            .and()
            .withClient("client-4")
            .secret(this.passwordEncoder.encode("client"))
            .authorizedGrantTypes("client_credentials")
            .scopes("read")
            .and()
            .withClient("client-5")
            .secret(this.passwordEncoder.encode("client"))
            .authorizedGrantTypes("client_credentials")
            .scopes("read");
}

这里先配置五个不同类型不同权限的客户端,客户端可能是资源服务器,也可能就是普通的应用程序

  • 配置UserInfo endpoint
@RestController
public class UserInfoController {

    @RequestMapping("/oauth/me")
    public Principal userInfo (Principal principal) {
        return principal;
    }

}

一个普通的REST API,为客户端提供用户详细信息以判断用户是否登陆、是否有权限访问资源

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/oauth/me")
                .and().authorizeRequests().anyRequest().access("#oauth2.hasScope('read')")
                .and().anonymous().disable();
    }

}

/oauth/me本身也是一种资源,只有提供合法token的client才能访问/oauth/me

  • 配置Spring security的默认登陆表单,所有请求都需要认证
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().authenticated()  // 所有请求都需要授权
            .and().formLogin()  // 使用默认的登陆界面
            .and().anonymous().disable();
}

2、资源服务器——SSO客户端(authorization_code)

SSO的基本流程:

  • 启动SSO客户端,自动注册一个OAuth Filter chain,匹配登陆URL(/login)
  • 访问资源受保护的资源,FilterSecurityInterceptor拦截后跳转到资源服务器登陆URL(/login)
  • 登陆URL(/login)匹配到OAuth Filter chain使用OAuth2ClientAuthenticationProcessingFilter进行权限认证
  • OAuth2ClientAuthenticationProcessingFilter发现没有token,而且grantType为authorization_code,所以跳转到验证服务器的/oauth/authorize获取token
  • 浏览器访问验证服务器的/oauth/authorize,验证服务器拦截请求之后跳转到验证服务器到登陆URL(/login)
  • 用户完成登陆之后,携带code跳转回资源服务器
  • 资源服务器根据code再次访问验证服务器获得token
  • 然后根据token访问认证服务器/oauth/me获得用户信息,完成登陆流程

SSO客户端配置:

server:
  port: 8081
  servlet:
    context-path: /client-1
security:
  oauth2:
    client:
      client-id: client-1
      client-secret: client
      access-token-uri: http://localhost:8080/server/oauth/token
      user-authorization-uri: http://localhost:8080/server/oauth/authorize
    resource:
      user-info-uri: http://localhost:8080/server/oauth/me
logging:
  level:
    org.springframework.web: DEBUG
    org.springframework.security: DEBUG
@Configuration
@EnableOAuth2Sso
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();  // 所有请求都需要验证
    }

}

@EnableOAuth2Sso启用SSO客户端配置,即拦截/login的filter chain

3、资源服务器——客户端模式(client_credentials)

第三方应用访问资源服务器受保护资源时需要提供自身的token、资源服务器根据自己的client_id和secret登陆认证服务器并验证第三方应用token的token是否有效,从而确定是否在资源服务器保存第三方应用的认证信息

  • 资源服务器配置信息:
server:
  port: 8082
  servlet:
    context-path: /client-2
security:
  oauth2:
    client:
      client-id: client-2
      client-secret: client
      access-token-uri: http://localhost:8080/server/oauth/token
      user-authorization-uri: http://localhost:8080/server/oauth/authorize
    resource:
      user-info-uri: http://localhost:8080/server/oauth/me
    authorization:
      check-token-access: http://localhost:8080/server/oauth/check_token
logging:
  level:
    org.springframework.web: DEBUG
    org.springframework.security: DEBUG
  • 配置RemoteTokenServices验证token、配置资源访问所需权限
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
    remoteTokenServices.setCheckTokenEndpointUrl(this.getAuthorizationServerProperties().getCheckTokenAccess());
    remoteTokenServices.setClientId(this.oAuth2ClientProperties.getClientId());
    remoteTokenServices.setClientSecret(this.oAuth2ClientProperties.getClientSecret());
    resources.tokenServices(remoteTokenServices);
}
  • 配置所有资源访问均需要对应的scope
@Override
public void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().access("#oauth2.hasScope('read')")
            .and().anonymous().disable();
}

4、访问资源服务器

第三方应用程序通过oAuth2RestTemplate访问资源服务器通过,oAuth2RestTemplate需要绑定client_id、secret以及认证服务器信息,从而获得对应的token(权限)

  • 客户端配置信息
server:
  port: 8083
  servlet:
    context-path: /client-3
security:
  oauth2:
    client:
      client-id: client-3
      client-secret: client
      access-token-uri: http://localhost:8080/server/oauth/token
      user-authorization-uri: http://localhost:8080/server/oauth/authorize
      grant-type: client_credentials
logging:
  level:
    org.springframework.web: DEBUG
    org.springframework.security: DEBUG
    com.chenlei: DEBUG
  • 配置oAuth2RestTemplate对应的Bean
@Configuration
public class AuthorizationClientConfig {

    @Bean
    @ConfigurationProperties(prefix = "security.oauth2.client")
    public ClientCredentialsResourceDetails getClientCredentialsResourceDetails() {
        return new ClientCredentialsResourceDetails();
    }

    @Bean
    public OAuth2RestOperations oAuth2RestOperations() {
        return new OAuth2RestTemplate(getClientCredentialsResourceDetails());
    }

}
  • 使用oAuth2RestTemplate访问资源服务器
@RestController
@RequestMapping("/resource")
public class ResourceController {

    private final Log logger = LogFactory.getLog(getClass());

    @Autowired
    private OAuth2RestOperations oAuth2RestTemplate;

    @RequestMapping("/")
    public String getResource() {
        logger.debug("I am client-3 and I will call client-4...");
        logger.debug("The client-4 say: " + oAuth2RestTemplate.getForObject("http://localhost:8084/client-4/resource/", String.class));
        logger.debug("The client-4 say: " + oAuth2RestTemplate.getForObject("http://localhost:8084/client-4/resource/web", String.class));
        logger.debug("The client-4 say: " + oAuth2RestTemplate.getForObject("http://localhost:8084/client-4/resource/method", String.class));
        logger.debug("The client-4 say: " + oAuth2RestTemplate.getForObject("http://localhost:8084/client-4/resource/cse/web", String.class));
        logger.debug("The client-4 say: " + oAuth2RestTemplate.getForObject("http://localhost:8084/client-4/resource/cse/method", String.class));
        return "I am client-3!!!";
    }

    @RequestMapping("/call/2")
    public String callClient_2() {
        logger.debug("I am client-3 and I will call client-2...");
        logger.debug("The client-2 say: " + oAuth2RestTemplate.getForObject("http://localhost:8082/client-2/resource/", String.class));
        return "I am client-3!!!";
    }

}

5、扩展或者自定义鉴权表达式

OAuth默认的OAuth2SecurityExpressionMethods提供一些常用的鉴权方法,特殊情况下我们需要扩展自己的鉴权方法,或者直接调用自己的外部方法。

Spring security提供两种方式配置权限拦截,一种是拦截URL并配置访问权限,称之为WebSecurity,另一种是在方法上加注解,控制方法访问权限,称之为MethodSecurity

  • 配置WebSecurity
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {

        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setCheckTokenEndpointUrl(this.getAuthorizationServerProperties().getCheckTokenAccess());
        remoteTokenServices.setClientId(this.oAuth2ClientProperties.getClientId());
        remoteTokenServices.setClientSecret(this.oAuth2ClientProperties.getClientSecret());

        ExtendOAuth2WebSecurityExpressionHandler extendOAuth2WebSecurityExpressionHandler = new ExtendOAuth2WebSecurityExpressionHandler();
        // 往ExpressionHandler中设置ApplicationContext,否则在鉴权时无法通过@调用CustomSecurityExpression,比如:@cse.permitAll(authentication, 'customSecurityExpression')
        extendOAuth2WebSecurityExpressionHandler.setApplicationContext(this.applicationContext);

        resources.tokenServices(remoteTokenServices).expressionHandler(extendOAuth2WebSecurityExpressionHandler);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/resource/web/**").access("#oauth2.hasMatchingScope('read')")  // 使用扩展的表达式鉴权
                .antMatchers("/resource/cse/web/**").access("@cse.permitAll(authentication, 'customSecurityExpression')")  // 使用自定义表达式鉴权
                .and().anonymous().disable();
    }
  • 配置MethodSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class GlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        ExtendOAuth2MethodSecurityExpressionHandler extendOAuth2MethodSecurityExpressionHandler = new ExtendOAuth2MethodSecurityExpressionHandler();
        // 往ExpressionHandler中设置ApplicationContext,否则在鉴权时无法通过@调用CustomSecurityExpression,比如:@cse.permitAll(authentication, 'customSecurityExpression')
        extendOAuth2MethodSecurityExpressionHandler.setApplicationContext(this.applicationContext);

        return extendOAuth2MethodSecurityExpressionHandler;
    }

}

6、启用JWT

Json web token是认证服务器使用私钥将用户详细信息签名加密参数的token,客户端可以访问认证服务器提供的endpoint获得对应的公钥,然后用公钥将jwt解密,从而获得对应的用户信息,省去了客户端频繁用token换取用户详细信息的过程,从而提高效率,减轻认证服务器的负担。

  • 生成密钥库文件,文件中包含一组公钥和私钥
LiondeMBP:tmp lion$ keytool -genkeypair -alias jwt -keyalg RSA -dname "CN=jwt, L=Wuhan, S=Hubei, C=CN" -keypass awesomePass -keystore jwt.jks -storepass awesomePass
  • 配置密钥对提取密码并配置AuthorizationServer支持JWT
server:
  port: 8080
  servlet:
    context-path: /server
logging:
  level:
    org.springframework.web: DEBUG
    org.springframework.security: DEBUG
    org.springframework.boot.autoconfigure: DEBUG
keystore:
  password: awesomePass
@Bean
public TokenStore tokenStore() {
    return new JwtTokenStore(jwtTokenEnhancer());
}

@Bean
public JwtAccessTokenConverter jwtTokenEnhancer() {
    String password = this.environment.getProperty("keystore.password");
    KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), password.toCharArray());
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setKeyPair(keyStoreKeyFactory.getKeyPair("jwt"));
    return converter;
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.tokenStore(this.tokenStore())
            .tokenEnhancer(jwtTokenEnhancer())
            .userApprovalHandler(this.userApprovalHandler());
}

7、事例源码

https://github.com/chenlein/springboot-oauth

<think>我们正在处理一个关于SpringSecurityOAuth2和JWT的完整代码示例请求。根据引用[1],我们知道SpringSecurityOAuth2提供了很多扩展点,并且这篇文章旨在消除其难以使用的误解。引用[2]提到了SpringBootSpringSecurity、JWT的集成。引用[3]展示了如何使用@EnableConfigurationProperties来加载特定bean。引用[4]给出了一个OAuth2授权请求的URL示例。引用[5]提到了SpringBoot应用初始化。由于用户要求一个完整的代码示例,我们将分步骤构建一个简单的OAuth2授权服务器和资源服务器,使用JWT令牌。注意:由于完整代码较长,我们将提供关键部分代码,并解释其作用。步骤:1.创建授权服务器(AuthorizationServer)2.创建资源服务器(ResourceServer)3.配置JWT我们将使用内存存储(用户、客户端信息)来简化示例。###1.授权服务器配置首先,我们需要配置授权服务器来颁发JWT令牌。```java@Configuration@EnableAuthorizationServerpublicclassAuthorizationServerConfigextendsAuthorizationServerConfigurerAdapter{@AutowiredprivateAuthenticationManagerauthenticationManager;@AutowiredprivatePasswordEncoderpasswordEncoder;@Overridepublicvoidconfigure(ClientDetailsServiceConfigurerclients)throwsException{clients.inMemory().withClient("client-id")//客户端ID.secret(passwordEncoder.encode("client-secret"))//客户端密钥.authorizedGrantTypes("authorization_code","refresh_token","password")//授权类型.scopes("read","write").redirectUris("http://localhost:8080/login/oauth2/code/messaging-client-oidc")//重定向URI.accessTokenValiditySeconds(3600)//访问令牌有效期.refreshTokenValiditySeconds(86400);//刷新令牌有效期}@Overridepublicvoidconfigure(AuthorizationServerEndpointsConfigurerendpoints){endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore())//使用JWT令牌存储.accessTokenConverter(accessTokenConverter());}@BeanpublicTokenStoretokenStore(){returnnewJwtTokenStore(accessTokenConverter());}@BeanpublicJwtAccessTokenConverteraccessTokenConverter(){JwtAccessTokenConverterconverter=newJwtAccessTokenConverter();converter.setSigningKey("secret-key");//设置签名密钥(实际应用中应使用安全的密钥)returnconverter;}}```###2.资源服务器配置资源服务器负责验证JWT令牌并保护资源。```java@Configuration@EnableResourceServerpublicclassResourceServerConfigextendsResourceServerConfigurerAdapter{@Overridepublicvoidconfigure(HttpSecurityhttp)throwsException{http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest().authenticated();}@BeanpublicTokenStoretokenStore(){returnnewJwtTokenStore(accessTokenConverter());}@BeanpublicJwtAccessTokenConverteraccessTokenConverter(){JwtAccessTokenConverterconverter=newJwtAccessTokenConverter();converter.setSigningKey("secret-key");//与授权服务器相同的密钥returnconverter;}}```###3.SpringSecurity配置我们需要配置SpringSecurity以进行用户认证。```java@Configuration@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@BeanpublicPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}@Overrideprotectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("password")).roles("USER");}@Override@BeanpublicAuthenticationManagerauthenticationManagerBean()throwsException{returnsuper.authenticationManagerBean();}@Overrideprotectedvoidconfigure(HttpSecurityhttp)throwsException{http.csrf().disable().authorizeRequests().antMatchers("/oauth/**").permitAll().anyRequest().authenticated().and().formLogin().permitAll();}}```###4.主应用类```java@SpringBootApplicationpublicclassOAuth2JwtApplication{publicstaticvoidmain(String[]args){SpringApplication.run(OAuth2JwtApplication.class,args);}}```###5.测试我们可以使用OAuth2的密码模式获取令牌:```curl-XPOST\http://localhost:8080/oauth/token\-H'Authorization:BasicY2xpZW50LWlkOmNsaWVudC1zZWNyZXQ='\-d'grant_type=password&username=user&password=password&scope=read'```这里,`Y2xpZW50LWlkOmNsaWVudC1zZWNyZXQ=`是`client-id:client-secret`的Base64编码。响应将包含访问令牌(JWT)和刷新令牌。###说明-上述示例使用内存存储,实际应用中应使用数据库。-签名密钥"secret-key"应替换为安全的密钥(如使用JKS文件或更长的随机字符串)。-授权服务器和资源服务器可以分开部署,这里为了简化放在一起。###注意事项-在SpringBoot2中,SpringSecurityOAuth2已被官方标记为废弃,推荐使用SpringSecurity5的新OAuth2支持。但考虑到用户要求使用SpringSecurityOAuth2,我们仍使用传统方式。关于SpringSecurity5的新OAuth2支持,我们可以在后续问题中讨论。§§相关问题§§1.如何在SpringBoot2中使用SpringSecurity5实现OAuth2和JWT?2.如何将上述示例中的内存存储改为数据库存储?3.如何实现OAuth2授权码模式(AuthorizationCode)与PKCE扩展?4.如何验证JWT令牌的签名?</think>### Spring Boot + Spring Security + OAuth2 + JWT 完整代码示例 下面是一个完整的OAuth2授权服务器和资源服务器集成JWT的代码实现,基于Spring Boot 2.x。包含核心配置、端点和安全控制。 --- #### 1. Maven依赖 (`pom.xml`) ```xml <dependencies> <!-- Spring Boot Starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- OAuth2 & JWT --> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.6.8</version> </dependency> <dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> <version>9.25.6</version> </dependency> </dependencies> ``` --- #### 2. 授权服务器配置 ```java @Configuration @EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private PasswordEncoder passwordEncoder; // 配置客户端详情 @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client-app") .secret(passwordEncoder.encode("secret")) .authorizedGrantTypes("password", "refresh_token") .scopes("read", "write") .accessTokenValiditySeconds(3600) // 1小时 .refreshTokenValiditySeconds(86400); // 24小时 } // 配置端点 @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints .authenticationManager(authenticationManager) .tokenStore(tokenStore()) .accessTokenConverter(accessTokenConverter()); } // JWT令牌存储 @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } // JWT转换器 @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("my-secret-key-12345"); // 对称密钥 return converter; } } ``` --- #### 3. 安全配置 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // 配置内存用户 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin") .password(passwordEncoder().encode("password")) .roles("ADMIN"); } // 暴露AuthenticationManager @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } // 密码编码器 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` --- #### 4. 资源服务器配置 ```java @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { // 配置资源权限规则 @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() .antMatchers("/private/**").authenticated() .anyRequest().denyAll(); } // JWT令牌配置 @Override public void configure(ResourceServerSecurityConfigurer config) { config.tokenServices(tokenServices()); } // 令牌服务 @Bean public DefaultTokenServices tokenServices() { DefaultTokenServices services = new DefaultTokenServices(); services.setTokenStore(tokenStore()); return services; } // JWT令牌存储 @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } // JWT转换器 @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("my-secret-key-12345"); return converter; } } ``` --- #### 5. 控制器示例 ```java @RestController public class ApiController { // 公开端点 @GetMapping("/public/hello") public String publicHello() { return "Hello Public!"; } // 受保护端点 @GetMapping("/private/hello") public String privateHello() { return "Hello Private!"; } } ``` --- #### 6. 主应用类 ```java @SpringBootApplication public class OAuth2JwtApplication { public static void main(String[] args) { SpringApplication.run(OAuth2JwtApplication.class, args); } } ``` --- ### 测试流程 1. **获取令牌** (使用密码模式): ```bash curl -X POST \ http://localhost:8080/oauth/token \ -H 'Authorization: Basic Y2xpZW50LWFwcDpzZWNyZXQ=' \ -d 'grant_type=password&username=admin&password=password' ``` - 响应示例: ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 3600, "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` 2. **访问受保护资源**: ```bash curl -X GET \ http://localhost:8080/private/hello \ -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' ``` --- ### 关键特性说明 1. **JWT令牌**: - 使用对称密钥签名 (`my-secret-key-12345`) - 包含标准声明:`sub`, `exp`, `iat`, `scope`等 - 可通过[jwt.io](https://jwt.io)解码验证 2. **安全端点**: - `/oauth/token` - 令牌颁发端点 - `/oauth/authorize` - 授权码端点(示例中使用密码模式) - `/private/**` - 需要有效JWT的端点 3. **扩展建议**: - 使用非对称密钥(RSA)替代对称密钥 - 添加自定义JWT声明(如用户ID) - 集成数据库存储客户端/用户信息 > **注意**:生产环境务必使用强密钥和HTTPS,此示例使用内存存储仅用于演示[^1][^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值