Web应用的验证授权(Authorization Code)

本文介绍如何使用OAuth2协议实现新浪微博应用的用户授权过程。主要包括两种授权方式:一是通过code方式获取授权,二是通过token直接获取授权。文中还提到了获取用户信息及发布微博的方法。
https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI

--response_type false string 支持的值包括 code 和token 默认值为code
--示例
response_type为token
请求
https://api.t.sina.com.cn/oauth2/authorize?client_id=123050457758183&redirect_uri=http://www.example.com/response&response_type=token
同意授权后会重定向
http://www.example.com/response#access_token=ACCESS_TOKEN&expires_in=250327040&refresh_token=REFRESH_TOKEN
response_type为code
请求
https://api.t.sina.com.cn/oauth2/authorize?client_id=123050457758183&redirect_uri=http://www.example.com/response&response_type=code
同意授权后会重定向
http://www.example.com/response&code=CODE
取自"http://open.weibo.com/wiki/Oauth2/authorize"

解决2:
先获取未授权的RequestToken,然后跳转到登录页要求用户登录,登录后,跳转到我的页面,得到授权的RequestToken,然后用这个RequestToken换取新浪微博授权的AccessToken。
在最后一步的返回值中有 oauth_token ,oauth_token_secret 和User_id
获取用户信息:
http://api.t.sina.com.cn/users/show.xml?source=appkey&user_id=11051


1. 申请应用时分配的AppKey?,AppKey应用需要申请?
2. Users/show 根据用户ID获取用户资料(授权用户)
3. Statuses/update发布一条微博信息
<think>我们正在讨论的是Spring Boot 2.2.0与OAuth2.0整合实现授权码模式(authorization code)。 根据之前的上下文,我们知道在Spring Boot 2.2.0中,官方推荐使用Spring Security 5.x的OAuth2客户端支持,而不再使用旧的Spring Security OAuth项目(该库已被废弃)。 因此,我们将使用`spring-boot-starter-oauth2-client`来实现授权码模式。 授权码模式流程: 1. 客户端将用户重定向到授权服务器的授权端点(authorization endpoint)。 2. 用户登录并授权。 3. 授权服务器将用户重定向回客户端(通过redirect_uri),并附带一个授权码(code)。 4. 客户端使用授权码向授权服务器的令牌端点(token endpoint)请求访问令牌(access token)和刷新令牌(refresh token)。 在Spring Boot 2.2.0中,我们可以通过以下步骤实现: 步骤1:添加依赖(pom.xml) 步骤2:配置OAuth2客户端(application.yml) 步骤3:配置Spring Security以启用OAuth2登录(授权码模式通常用于登录) 步骤4:编写控制器 注意:在授权码模式中,我们通常需要一个用户代理(如浏览器)来重定向用户。 下面我们详细说明: ### 1. 添加依赖 除了基本的Spring Boot Web和Security依赖,需要添加`spring-boot-starter-oauth2-client`: ```xml <dependencies> <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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> </dependencies> ``` ### 2. 配置OAuth2客户端(application.yml) 配置示例(这里以GitHub为例,也可以自定义其他OAuth2提供者): ```yaml spring: security: oauth2: client: registration: github: # 注册ID,可以任意命名,但需要与提供者对应 client-id: your-github-client-id client-secret: your-github-client-secret authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" # 注意:这个URI是Spring Security OAuth2客户端默认的 # 可选:配置作用域 scope: user,public_repo # 如果使用自定义的授权服务器,则需要配置provider provider: github: authorization-uri: https://github.com/login/oauth/authorize token-uri: https://github.com/login/oauth/access_token user-info-uri: https://api.github.com/user # 如果使用自定义的授权服务器,通常还需要配置用户名的属性名(用于从用户信息中提取用户名) user-name-attribute: login ``` 注意:`{baseUrl}`会被替换为当前应用的基础URL。 ### 3. 安全配置 创建一个配置类,启用Web安全并配置OAuth2登录: ```java import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/", "/public/**").permitAll() .anyRequest().authenticated() .and() .oauth2Login(); // 启用OAuth2登录 } } ``` 这样,当用户访问需要认证的资源时,会自动重定向到授权服务器的登录页面(例如GitHub的登录授权页面)。 ### 4. 编写控制器 我们可以创建一个简单的控制器来展示用户信息: ```java import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @GetMapping("/user") public String user(@AuthenticationPrincipal OAuth2User principal) { return "Hello, " + principal.getAttribute("name"); } } ``` ### 5. 启动应用 启动应用后,访问`/user`端点,将会被重定向到GitHub进行授权授权后,GitHub会将用户重定向回我们的应用(即配置的redirect_uri),然后我们的应用会使用授权码去获取访问令牌,并最终获取用户信息。 ### 自定义授权服务器 如果我们不想使用GitHub等第三方服务,而是使用自己的授权服务器,那么我们需要配置自己的provider。例如,假设我们有一个授权服务器运行在本地: ```yaml spring: security: oauth2: client: registration: custom: # 自定义的注册ID client-id: custom-client-id client-secret: custom-client-secret authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/custom" # 注意这里的registrationId要匹配 scope: read,write provider: custom: # 与上面的注册ID对应 authorization-uri: http://localhost:9000/oauth/authorize token-uri: http://localhost:9000/oauth/token user-info-uri: http://localhost:9000/userinfo user-name-attribute: sub ``` ### 重要说明 - 授权服务器必须支持授权码模式,并且配置的redirect_uri必须与授权服务器上注册的redirect_uri匹配。 - Spring Security OAuth2客户端默认提供了处理授权码回调的端点`/login/oauth2/code/*`,这个端点由`OAuth2LoginAuthenticationFilter`处理。 ### 授权码模式的安全性 授权码模式是OAuth2中最安全的模式之一,因为令牌不会经过浏览器(用户代理),而是直接从客户端后端与授权服务器交互获取。因此,它适用于有后端的Web应用。 注意:在Spring Boot 2.2.0中,我们使用的是Spring Security 5的OAuth2客户端支持,因此不需要像旧版本那样使用`@EnableOAuth2Client`或`@EnableAuthorizationServer`等注解(这些属于已被废弃的spring-security-oauth2项目)。 引用说明: 我们在回答中参考了旧版本中配置授权服务器的方式(引用[1]),但在Spring Boot 2.2.0中,官方推荐使用新的方式,即通过`oauth2Login()`和客户端注册配置。同时,关于Basic认证的说明(引用[2])在获取令牌的步骤中可能会被用到(客户端在换取令牌时需要认证),但在Spring Security 5的客户端中,这些细节已经被封装。 因此,我们按照新的方式实现了授权码模式。 如果用户需要自己搭建授权服务器,那么在Spring Boot 2.2.0中,官方不再提供支持(因为AuthorizationServer已被废弃),建议使用更专业的授权服务器(如Keycloak)或者等待Spring Authorization Server项目成熟(目前Spring官方推出了新的Spring Authorization Server项目,但需要Spring Boot 2.4+)。 相关问题: 1. 如何在Spring Boot中实现OAuth2授权服务器? 2. 授权码模式与隐式模式的区别? 3. 如何通过OAuth2客户端获取用户信息? </think>以下是Spring Boot 2.2.0集成OAuth 2.0实现**授权码模式**的详细说明: ### 核心实现步骤 #### 1. 添加依赖(pom.xml) ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.2.0.RELEASE</version> </dependency> ``` #### 2. 配置授权服务器 ```java @Configuration @EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { private final PasswordEncoder passwordEncoder; public AuthServerConfig(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("web_app") // 客户端ID .secret(passwordEncoder.encode("secret123")) // 客户端密钥 .authorizedGrantTypes("authorization_code", "refresh_token") // 授权类型 .scopes("read", "write") // 权限范围 .redirectUris("http://localhost:8080/login/oauth2/code/web_app") // 重定向URI .autoApprove(true); // 自动批准授权 } } ``` #### 3. 配置资源服务器 ```java @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/public/**").permitAll() .anyRequest().authenticated(); } } ``` #### 4. 安全配置 ```java @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login**").permitAll() .anyRequest().authenticated() .and() .oauth2Login() // 启用OAuth2登录 .loginPage("/login") // 自定义登录页 .and() .logout().permitAll(); } } ``` #### 5. application.yml配置 ```yaml server: port: 8080 security: oauth2: client: registration: web_app: # 客户端注册ID client-id: web_app client-secret: secret123 authorization-grant-type: authorization_code redirect-uri: http://localhost:8080/login/oauth2/code/web_app scope: read,write provider: web_app: # 提供者ID authorization-uri: http://localhost:8080/oauth/authorize token-uri: http://localhost:8080/oauth/token user-info-uri: http://localhost:8080/user/me ``` ### 授权码流程详解 1. **用户访问客户端** 用户访问受保护资源`/secured`,被重定向到登录页 `http://localhost:8080/login` 2. **重定向到授权端点** 点击"Login with OAuth"按钮,重定向到授权端点: `http://localhost:8080/oauth/authorize?response_type=code&client_id=web_app&redirect_uri=http://localhost:8080/login/oauth2/code/web_app` 3. **用户授权** 用户在授权页面同意授权(如果配置了`autoApprove=true`则自动跳过) 4. **获取授权码** 授权服务器返回授权码到重定向URI: `http://localhost:8080/login/oauth2/code/web_app?code=AUTHORIZATION_CODE` 5. **换取访问令牌** 客户端使用授权码向令牌端点请求令牌: ```http POST /oauth/token Authorization: Basic d2ViX2FwcDpzZWNyZXQxMjM= # Basic认证(client_id:client_secret)[^2] Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=http://localhost:8080/login/oauth2/code/web_app ``` 6. **获取资源** 使用访问令牌访问资源: ```http GET /api/resources Authorization: Bearer ACCESS_TOKEN ``` ### 关键特性说明 1. **安全机制** - 使用Basic认证保护令牌端点(`Authorization: Basic base64(client_id:client_secret)`)[^2] - 短期授权码(通常5分钟有效期) - HTTPS强制推荐(生产环境必需) 2. **端点配置** | 端点 | 路径 | 作用 | |------|------|------| | 授权端点 | `/oauth/authorize` | 获取授权码 | | 令牌端点 | `/oauth/token` | 换取访问令牌 | | 用户信息 | `/user/me` | 获取用户详情 | 3. **会话管理** Spring Security自动管理: - 存储授权请求会话 - 防止CSRF攻击 - 令牌存储在`OAuth2AuthorizedClient`对象中 ### 最佳实践 1. **自定义同意页面** ```java @Controller public class ConsentController { @GetMapping("/oauth/confirm_access") public String consentPage(Model model) { // 添加自定义授权信息到模型 return "custom-consent"; } } ``` 2. **令牌存储策略** 默认使用内存存储,生产环境推荐: ```java @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); // 或 RedisTokenStore } ``` 3. **范围验证** 在资源服务器验证访问范围: ```java http.authorizeRequests() .antMatchers("/admin/**").access("#oauth2.hasScope('write')"); ``` --- ### 常见问题解决 **Q: 重定向URI不匹配错误** ```log Invalid redirect_uri parameter ``` **解决方案**:确保`redirect-uri`配置与注册URI完全一致,包括大小写和结尾斜杠 **Q: 无效的授权码错误** ```log Invalid authorization code: AUTHORIZATION_CODE ``` **解决方案**: 1. 检查授权码有效期(通常5分钟) 2. 确保授权码未重复使用 **Q: CSRF令牌失效** **解决方案**:增加会话超时时间或使用分布式会话存储 ```yaml server: servlet: session: timeout: 1800 # 30分钟 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值