• 作者:老汪软件技巧
  • 发表时间:2024-10-14 10:03
  • 浏览量:

前言

有没有一种方式,不需要告诉第三方你的账号、密码,通过简单的授权,第三方就可以看到授权范围内的部分数据呢?

当然有,这就是目前盛行的 OAuth 授权流程。

OAuth 2.0 是一种用于授权的开放标准,广泛应用于互联网应用中。它允许第三方应用程序在用户授权的情况下,访问用户在某一服务提供商(如Google、Facebook等)上的资源,而不需要暴露用户的凭据(如用户名和密码)。

以下是 OAuth 2.0 的基本流程:

用户授权:用户在第三方应用程序上点击授权按钮,跳转到服务提供商的授权页面。授权码(Authorization Code) :用户在服务提供商的授权页面上同意授权后,服务提供商会将用户重定向回第三方应用程序,并附带一个授权码。获取访问令牌(Access Token) :第三方应用程序使用授权码向服务提供商请求访问令牌。访问资源:第三方应用程序使用访问令牌访问用户在服务提供商上的资源。

我们以登录某第三方应用为例,其已接入微信登录能力,我们只需要通过简单的授权,即可实现正常登录:

OAuth 2.0

我们仍然以微信提供的 OAuth2.0 认证为例,微信提供了OAuth 2.0认证和授权服务,允许第三方应用在用户授权的情况下,访问用户的微信账户信息。

以下是微信 OAuth 2.0 授权码流程:

1. 注册微信开放平台应用

首先,需要在微信开放平台上注册应用,以获取 AppID 和 AppSecret。步骤如下:

访问[微信开放平台]注册并登录开发者账号。创建一个新的应用,填写相关信息。记录下 AppID 和 AppSecret。2. 配置 OAuth 2.0 端点

微信的 OAuth 2.0 端点包括授权端点和令牌端点:

3. 登录授权流程

大致流程:

进入你的应用页面,如果是未登录状态,则从后端获取登录授权页(/login)后端返回微信登录授权页面你进行【点击授权】微信将用户重定向回你在微信开放平台上配置的回调地址,并在 URL 中附带授权码。前端携带授权码 code 请求后端,后端通过授权码 code 调用微信开放接口获取 access_token 及用户信息授权完成,后端记录登录状态

_第三方账号授权_第三方授权登录

package com.example.demo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@WebServlet("/wechat-oauth2")
public class WeChatOAuth2Servlet extends HttpServlet {
    private static final String APP_ID = "你的AppID";
    private static final String APP_SECRET = "你的AppSecret";
    private static final String AUTHORIZATION_URL = "https://open.weixin.qq.com/connect/oauth2/authorize";
    private static final String TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
    private static final String USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo";
    private static final String REDIRECT_URI = "http://localhost:8080/wechat-oauth2/callback";
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String action = req.getParameter("action");
        if ("login".equals(action)) {
            // 重定向到微信的授权页面
            String authorizationUrl = String.format("%s?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect",
                    AUTHORIZATION_URL, APP_ID, REDIRECT_URI);
            resp.sendRedirect(authorizationUrl);
            
        } else if ("callback".equals(action)) { // 用户授权后,将用户重定向回你的应用的URL,并附带授权码。这个URL是你在微信开放平台上配置的回调地址(Redirect URI)
            // 获取授权码
            String code = req.getParameter("code");
            // 使用授权码获取访问令牌
            String accessToken = getAccessToken(code);
            // 使用访问令牌获取用户信息
            String userInfo = getUserInfo(accessToken);
            resp.getWriter().write("用户信息:" + userInfo);
        } else {
            resp.getWriter().write("欢迎使用微信OAuth 2.0示例!
登录"
); } } private String getAccessToken(String code) throws IOException { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { String url = String.format("%s?appid=%s&secret=%s&code=%s&grant_type=authorization_code", TOKEN_URL, APP_ID, APP_SECRET, code); HttpPost httpPost = new HttpPost(url); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { String responseBody = EntityUtils.toString(response.getEntity()); Map responseMap = new ObjectMapper().readValue(responseBody, Map.class); return (String) responseMap.get("access_token"); } } } private String getUserInfo(String accessToken) throws IOException { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { String url = String.format("%s?access_token=%s&openid=%s", USER_INFO_URL, accessToken, APP_ID); HttpPost httpPost = new HttpPost(url); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { return EntityUtils.toString(response.getEntity()); } } } }

以上主要展示处理微信的 OAuth 2.0 授权码流程,包括前端引导用户登录、微信重定向回后端、后端处理回调、获取访问令牌和用户信息。

前端与后端的交互

在这个流程中,前端的主要任务是引导用户点击登录链接,并处理微信的重定向。后端负责处理回调请求,提取授权码,获取访问令牌,并获取用户信息。

前端引导用户登录:前端页面上有一个登录链接,用户点击后,前端将用户重定向到微信的授权页面。微信重定向回后端:微信在用户授权后,将用户重定向回后端的回调地址,并附带授权码。后端处理回调:后端接收到回调请求,提取授权码,并使用授权码获取访问令牌和用户信息。

微信 OAuth 2.0 授权码流程中,如何处理访问令牌的过期和刷新?

在微信 OAuth 2.0 授权码流程中,访问令牌(Access Token)是有有效期的,通常为2小时。

当访问令牌过期时,你需要使用刷新令牌(Refresh Token)来获取新的访问令牌。刷新令牌的有效期通常较长,可以是 30 天或更长。

访问令牌过期和刷新的步骤:

获取刷新令牌:在获取访问令牌 access_token 时,微信会同时返回一个刷新令牌 refresh_token。存储令牌:后端存储令牌,并做好过期时间控制。检测访问令牌是否过期:在每次使用访问令牌访问资源时,检测是否返回了令牌过期的错误。使用刷新令牌获取新的访问令牌:当访问令牌过期时,使用刷新令牌获取新的访问令牌。OAuth2.0 经典应用场景

OAuth2.0 目前已经应用非常广泛,包括但不限于:

1. 社交登录(Social Login)

社交登录是 OAuth 2.0 最常见的应用之一。用户可以使用他们在社交媒体平台(如 微信、微博、掘金等)上的账户登录第三方应用,而无需创建新的账户。

2. API 访问授权

OAuth 2.0 常用于授权第三方应用访问用户的 API 资源。例如,用户可以授权一个应用访问他们的 巨量引擎(抖音)广告投放数据、GitHub 仓库等。

3. 单点登录(Single Sign-On, SSO)

单点登录允许用户在多个应用之间无缝切换,而无需每次都进行身份验证。OAuth 2.0 通常与 OpenID Connect 结合使用,以实现单点登录。

...