详细分析Java中的AuthRequest类(附Demo)

目录

  • 前言
  • 1. 基本知识
  • 2. Demo
  • 3. 实战

前言

公共接口,定义了对第三方平台进行授权、登录、撤销授权和刷新 token 的操作

1. 基本知识

先看源码基本API接口:

import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;

/**
 * JustAuth {@code Request}公共接口,所有平台的{@code Request}都需要实现该接口
 * <p>
 * {@link AuthRequest#authorize()}
 * {@link AuthRequest#authorize(String)}
 * {@link AuthRequest#login(AuthCallback)}
 * {@link AuthRequest#revoke(AuthToken)}
 * {@link AuthRequest#refresh(AuthToken)}
 *
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
 * @since 1.8
 */
public interface AuthRequest {

    /**
     * 返回授权url,可自行跳转页面
     * <p>
     * 不建议使用该方式获取授权地址,不带{@code state}的授权地址,容易受到csrf攻击。
     * 建议使用{@link AuthDefaultRequest#authorize(String)}方法生成授权地址,在回调方法中对{@code state}进行校验
     *
     * @return 返回授权地址
     */
    @Deprecated
    default String authorize() {
        throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
    }

    /**
     * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
     *
     * @param state state 验证授权流程的参数,可以防止csrf
     * @return 返回授权地址
     */
    default String authorize(String state) {
        throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
    }

    /**
     * 第三方登录
     *
     * @param authCallback 用于接收回调参数的实体
     * @return 返回登录成功后的用户信息
     */
    default AuthResponse login(AuthCallback authCallback) {
        throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
    }

    /**
     * 撤销授权
     *
     * @param authToken 登录成功后返回的Token信息
     * @return AuthResponse
     */
    default AuthResponse revoke(AuthToken authToken) {
        throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
    }

    /**
     * 刷新access token (续期)
     *
     * @param authToken 登录成功后返回的Token信息
     * @return AuthResponse
     */
    default AuthResponse refresh(AuthToken authToken) {
        throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
    }
}

大致方法如下:

  • authorize():返回授权 URL,但已被标记为过时 (@Deprecated)。不建议使用此方法获取授权地址,因为不带 state 的授权地址容易受到 CSRF 攻击
  • authorize(String state):返回带 state 参数的授权 URL,授权回调时会带上这个 state,用于验证授权流程的参数,防止 CSRF 攻击
  • login(AuthCallback authCallback):第三方登录方法,用于接收回调参数的实体,并返回登录成功后的用户信息
  • revoke(AuthToken authToken):撤销授权方法,用于撤销登录成功后返回的 Token 信息
  • refresh(AuthToken authToken):刷新 Access Token 方法,用于续期登录成功后返回的 Token 信息

2. Demo

根据上述接口,简单测试下接口功能:

制造一个第三方的类:

package com.example.test;

import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.request.AuthRequest;

public class GitHubAuthProvider implements AuthRequest {

    @Override
    public String authorize(String state) {
        // 返回 GitHub 授权 URL,并将 state 参数添加到 URL 中
        return "https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&state=" + state;
    }

    @Override
    public AuthResponse login(AuthCallback authCallback) {
        // 模拟 GitHub 登录成功后返回的用户信息
        return new AuthResponse(200, "Success", "GitHubUser,github@example.com");
    }

    @Override
    public AuthResponse revoke(AuthToken authToken) {
        // 撤销授权的具体实现
        return new AuthResponse(200, "Success", "Authorization revoked successfully");
    }

    @Override
    public AuthResponse refresh(AuthToken authToken) {
        // 刷新 Access Token 的具体实现
        return new AuthResponse(200, "Success", "Access Token refreshed successfully");
    }
}

对应的接口测试类如下:

import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.request.AuthRequest;

public class test {

    public static void main(String[] args) {
        // 创建一个第三方平台的具体实现对象
        AuthRequest authRequest = new GitHubAuthProvider();

        // 获取授权 URL,传入 state 参数
        String authorizeUrl = authRequest.authorize("random_state_parameter");
        System.out.println("Authorize URL: " + authorizeUrl);

        // 模拟第三方登录操作,传入 AuthCallback 实体
        AuthResponse authResponse = authRequest.login(new AuthCallback());
        System.out.println("Login response: " + authResponse);

        // 模拟撤销授权操作,传入登录成功后返回的 Token 信息
        AuthToken authToken = new AuthToken();
        AuthResponse revokeResponse = authRequest.revoke(authToken);
        System.out.println("Revoke response: " + revokeResponse);

        // 模拟刷新 Access Token 操作,传入登录成功后返回的 Token 信息
        AuthResponse refreshResponse = authRequest.refresh(authToken);
        System.out.println("Refresh response: " + refreshResponse);
    }
}

截图如下:(默认的 toString() 方法返回的对象字符串表示形式)

在这里插入图片描述

3. 实战

上述Demo只是一个简易版

在实战中应对各个不同的应用,可以写个模板类

import java.util.Objects;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.request.AuthAlipayRequest;
import me.zhyd.oauth.request.AuthBaiduRequest;
import me.zhyd.oauth.request.AuthCodingRequest;
import me.zhyd.oauth.request.AuthCsdnRequest;
import me.zhyd.oauth.request.AuthDingTalkRequest;
import me.zhyd.oauth.request.AuthDouyinRequest;
import me.zhyd.oauth.request.AuthElemeRequest;
import me.zhyd.oauth.request.AuthFacebookRequest;
import me.zhyd.oauth.request.AuthGiteeRequest;
import me.zhyd.oauth.request.AuthGithubRequest;
import me.zhyd.oauth.request.AuthGitlabRequest;
import me.zhyd.oauth.request.AuthGoogleRequest;
import me.zhyd.oauth.request.AuthHuaweiRequest;
import me.zhyd.oauth.request.AuthKujialeRequest;
import me.zhyd.oauth.request.AuthLinkedinRequest;
import me.zhyd.oauth.request.AuthMeituanRequest;
import me.zhyd.oauth.request.AuthMiRequest;
import me.zhyd.oauth.request.AuthMicrosoftRequest;
import me.zhyd.oauth.request.AuthOschinaRequest;
import me.zhyd.oauth.request.AuthPinterestRequest;
import me.zhyd.oauth.request.AuthQqRequest;
import me.zhyd.oauth.request.AuthRenrenRequest;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.request.AuthStackOverflowRequest;
import me.zhyd.oauth.request.AuthTaobaoRequest;
import me.zhyd.oauth.request.AuthTeambitionRequest;
import me.zhyd.oauth.request.AuthToutiaoRequest;
import me.zhyd.oauth.request.AuthTwitterRequest;
import me.zhyd.oauth.request.AuthWeChatEnterpriseRequest;
import me.zhyd.oauth.request.AuthWeChatMpRequest;
import me.zhyd.oauth.request.AuthWeChatOpenRequest;
import me.zhyd.oauth.request.AuthWeiboRequest;
import org.springblade.core.social.props.SocialProperties;

public class SocialUtil {
    public SocialUtil() {
    }

    public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) {
        AuthDefaultSource authSource = (AuthDefaultSource)Objects.requireNonNull(AuthDefaultSource.valueOf(source.toUpperCase()));
        AuthConfig authConfig = (AuthConfig)socialProperties.getOauth().get(authSource);
        if (authConfig == null) {
            throw new AuthException("未获取到有效的Auth配置");
        } else {
            AuthRequest authRequest = null;
            switch (authSource) {
                case GITHUB:
                    authRequest = new AuthGithubRequest(authConfig);
                    break;
                case GITEE:
                    authRequest = new AuthGiteeRequest(authConfig);
                    break;
                case OSCHINA:
                    authRequest = new AuthOschinaRequest(authConfig);
                    break;
                case QQ:
                    authRequest = new AuthQqRequest(authConfig);
                    break;
                case WECHAT_OPEN:
                    authRequest = new AuthWeChatOpenRequest(authConfig);
                    break;
                case WECHAT_ENTERPRISE:
                    authRequest = new AuthWeChatEnterpriseRequest(authConfig);
                    break;
                case WECHAT_MP:
                    authRequest = new AuthWeChatMpRequest(authConfig);
                    break;
                case DINGTALK:
                    authRequest = new AuthDingTalkRequest(authConfig);
                    break;
                case ALIPAY:
                    authRequest = new AuthAlipayRequest(authConfig);
                    break;
                case BAIDU:
                    authRequest = new AuthBaiduRequest(authConfig);
                    break;
                case WEIBO:
                    authRequest = new AuthWeiboRequest(authConfig);
                    break;
                case CODING:
                    authRequest = new AuthCodingRequest(authConfig);
                    break;
                case CSDN:
                    authRequest = new AuthCsdnRequest(authConfig);
                    break;
                case TAOBAO:
                    authRequest = new AuthTaobaoRequest(authConfig);
                    break;
                case GOOGLE:
                    authRequest = new AuthGoogleRequest(authConfig);
                    break;
                case FACEBOOK:
                    authRequest = new AuthFacebookRequest(authConfig);
                    break;
                case DOUYIN:
                    authRequest = new AuthDouyinRequest(authConfig);
                    break;
                case LINKEDIN:
                    authRequest = new AuthLinkedinRequest(authConfig);
                    break;
                case MICROSOFT:
                    authRequest = new AuthMicrosoftRequest(authConfig);
                    break;
                case MI:
                    authRequest = new AuthMiRequest(authConfig);
                    break;
                case TOUTIAO:
                    authRequest = new AuthToutiaoRequest(authConfig);
                    break;
                case TEAMBITION:
                    authRequest = new AuthTeambitionRequest(authConfig);
                    break;
                case PINTEREST:
                    authRequest = new AuthPinterestRequest(authConfig);
                    break;
                case RENREN:
                    authRequest = new AuthRenrenRequest(authConfig);
                    break;
                case STACK_OVERFLOW:
                    authRequest = new AuthStackOverflowRequest(authConfig);
                    break;
                case HUAWEI:
                    authRequest = new AuthHuaweiRequest(authConfig);
                    break;
                case KUJIALE:
                    authRequest = new AuthKujialeRequest(authConfig);
                    break;
                case GITLAB:
                    authRequest = new AuthGitlabRequest(authConfig);
                    break;
                case MEITUAN:
                    authRequest = new AuthMeituanRequest(authConfig);
                    break;
                case ELEME:
                    authRequest = new AuthElemeRequest(authConfig);
                    break;
                case TWITTER:
                    authRequest = new AuthTwitterRequest(authConfig);
            }

            if (null == authRequest) {
                throw new AuthException("未获取到有效的Auth配置");
            } else {
                return (AuthRequest)authRequest;
            }
        }
    }
}

类似的Github第三方平台如下:(以下类为API自带的)

import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.GlobalAuthUtils;

import java.util.Map;

/**
 * Github登录
 *
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
 * @since 1.0.0
 */
public class AuthGithubRequest extends AuthDefaultRequest {

    public AuthGithubRequest(AuthConfig config) {
        super(config, AuthDefaultSource.GITHUB);
    }

    public AuthGithubRequest(AuthConfig config, AuthStateCache authStateCache) {
        super(config, AuthDefaultSource.GITHUB, authStateCache);
    }

    @Override
    protected AuthToken getAccessToken(AuthCallback authCallback) {
        String response = doPostAuthorizationCode(authCallback.getCode());
        Map<String, String> res = GlobalAuthUtils.parseStringToMap(response);

        this.checkResponse(res.containsKey("error"), res.get("error_description"));

        return AuthToken.builder()
            .accessToken(res.get("access_token"))
            .scope(res.get("scope"))
            .tokenType(res.get("token_type"))
            .build();
    }

    @Override
    protected AuthUser getUserInfo(AuthToken authToken) {
        String response = doGetUserInfo(authToken);
        JSONObject object = JSONObject.parseObject(response);

        this.checkResponse(object.containsKey("error"), object.getString("error_description"));

        return AuthUser.builder()
            .rawUserInfo(object)
            .uuid(object.getString("id"))
            .username(object.getString("login"))
            .avatar(object.getString("avatar_url"))
            .blog(object.getString("blog"))
            .nickname(object.getString("name"))
            .company(object.getString("company"))
            .location(object.getString("location"))
            .email(object.getString("email"))
            .remark(object.getString("bio"))
            .gender(AuthUserGender.UNKNOWN)
            .token(authToken)
            .source(source.toString())
            .build();
    }

    private void checkResponse(boolean error, String error_description) {
        if (error) {
            throw new AuthException(error_description);
        }
    }

}

后续在使用过程的代码如下:

@NonDS
@Slf4j
@RestController
@AllArgsConstructor
@ConditionalOnProperty(value = "social.enabled", havingValue = "true")
public class BladeSocialEndpoint {

	private final SocialProperties socialProperties;

	/**
	 * 授权完毕跳转
	 */
	@RequestMapping("/oauth/render/{source}")
	public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
		String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
		response.sendRedirect(authorizeUrl);
	}

	/**
	 * 获取认证信息
	 */
	@RequestMapping("/oauth/callback/{source}")
	public Object login(@PathVariable("source") String source, AuthCallback callback) {
		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
		return authRequest.login(callback);
	}

	/**
	 * 撤销授权
	 */
	@RequestMapping("/oauth/revoke/{source}/{token}")
	public Object revokeAuth(@PathVariable("source") String source, @PathVariable("token") String token) {
		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
		return authRequest.revoke(AuthToken.builder().accessToken(token).build());
	}

	/**
	 * 续期令牌
	 */
	@RequestMapping("/oauth/refresh/{source}")
	public Object refreshAuth(@PathVariable("source") String source, String token) {
		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
		return authRequest.refresh(AuthToken.builder().refreshToken(token).build());
	}


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/559159.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

提升测试效率,专业方案揭秘

提升测试效率是软件开发中一个永恒的主题&#xff0c;它不仅关乎项目能否按期完成&#xff0c;更影响着软件产品的质量与用户体验。随着敏捷开发、持续集成等方法论的普及&#xff0c;如何在有限的时间内进行高效、全面的测试成为了开发者和测试人员面临的挑战。 在传统模式中&…

Windows 平台上面管理服务器程式的高级 QoS 策略

在 Windows 平台上面&#xff0c;目前有两个办法来调整应用程式的 QoS 策略设置&#xff0c;一种是通过程式设置&#xff0c;一种是通过 “Windows 组策略控制”。 在阅读本文之前&#xff0c;您需要先查阅本人以下的几篇文献&#xff0c;作为前情提示&#xff1a; VC Windows…

数据质量与策略:解锁生成式AI潜力的关键步骤

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

每日一题(L2-011):玩转二叉树--建树+层序遍历

与L2-006近乎相同&#xff0c;先建树&#xff0c;然后遍历 #include<bits/stdc.h> using namespace std; int in[35]; int pre[35]; typedef struct Tree{int num;Tree* left;Tree* right; }T;T * build(int in1,int in2,int pre1,int pre2){T * tnew T;t->numpre[pr…

战姬物语部署

一.准备环境 #关闭seliunx和防火墙 setenforce 0 systemctl stop firewalld systemctl disable firewalld #配置源&#xff0c;并安装常用工 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo curl -o /etc/yum.repos.d/epel.repo …

Leetcode 86. 分隔链表

题目链接&#xff1a; 86. 分隔链表 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/partition-list/description/ 题目&#xff1a; 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出…

深入探究图像增强(C语言实现)

我们将从基础出发使用C语言进行图像处理与分析&#xff0c;重点讨论图像增强和平滑技术。图像增强技术旨在通过增加对比度、亮度和整体清晰度来改善图像的视觉质量。另一方面&#xff0c;图像平滑方法则用于减少噪声并减少图像中的突变&#xff0c;使图像更加均匀和视觉上吸引人…

利用二维码定位技术实现桌面机器人简易定位方案(上篇)

目录 1、前言2、二维码的定位标签识别原理3、生成定位标签3、基于定位标签的物体识别与定位 1、前言 机械手臂尤其是工业场景下大部分的应用是在一个平面&#xff08;桌面&#xff09;内完成一些抓取工作。一般可以用示教方式完成重复步骤。但是示教方式&#xff0c;对于一些活…

过氧化氢滴定方法可用的PFA器皿有哪些?

滴定液:KMnO4标准溶液 试液:H2O2商品液(3%)&#xff0c;H2SO4 (3.0mol/L ) 指示剂:酚酞指示剂 仪器:分析天平&#xff0c;PFA酸式滴定管50mL&#xff0c;PFA 移液管10mL/25mL、PFA 容量瓶250mL、PFA锥形瓶250mL 1、KMnO4标准溶液浓度的标定(见实验:高锰酸钾标准溶液的配制与…

记一次普通的单表查询sql优化,去掉文件排序

一现象&#xff1a; 有空观察了线上某个sql语句执行计划&#xff0c;发现在500多毫秒左右&#xff0c;打算进行下优化。 二步骤&#xff1a; 对查询列assessment_periodic_id、assessment_user_id、create_time添加了组合索引并指定了倒叙。加入create_time 使查询结果不需要在…

阿里云OSS 存储对象的注册与使用

目录 一、什么是阿里云OSS 二、 点击免费试用 2.1 选择第一个&#xff0c;点击免费试用 ​编辑 2.2 登录管理控制台 2.3 进入Bucket 2.4、在阿里云网站上的个人中心配置Accesskey,查询accessKeyId和accessKeySecret。 2.5、进入AccssKey管理页面应该会出现下图提示&…

通用大模型研究重点之五:llama family

LLAMA Family decoder-only类型 LLaMA&#xff08;Large Language Model AI&#xff09;在4月18日公布旗下最大模型LLAMA3&#xff0c;参数高达4000亿。目前meta已经开源了80亿和700亿版本模型&#xff0c;主要升级是多模态、长文本方面工作。 模型特点&#xff1a;采用标准的…

Java面试八股之Java异常处理完成后,Exception对象会发生什么变化

Java异常处理完成后&#xff0c;Exception对象会发生什么变化 这个题的难度在于&#xff0c;看到题之后可能不知道面试官想问什么。在面试中&#xff0c;如果实在没明白&#xff0c;可以让面试官再深入阐述一下。 Java异常处理完成后&#xff0c;Exception对象失去了程序中的…

自定义Blazor单文件Web程序端口

#接 上篇 Mysql快速迁移版的制作过程# 上一篇《Mysql8快速迁移版的制作过程》完成了快速迁移的数据库的准备&#xff0c;今天接着讲基于Blazor的Web程序快速迁移版的制作。 单文件发布的难点不在发布而是因为程序系统默认给了个5001的端口&#xff0c;而是如何能够让用户自定…

Leetcode 11.盛最多水的容器(暴力->双指针)

给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。 示例 …

Postman调用OpenApi接口

首先你需要科学上网。。。。。 请求方式&#xff1a;post 请求地址&#xff1a;https://api.openai.com/v1/chat/completions 请求头&#xff1a; Authorization : Bearer key Content-Type : application/json Body : { "messages": [{ "role": &quo…

【精简改造版】大型多人在线游戏BrowserQuest服务器Golang框架解析(1)——功能清单

1.匿名登录 2.服务连接 3.新手引导 4.随机出生点 5.界面布局 6.玩法帮助 7.NPC会话 8.成就系统 9.成就达成 10.用户聊天 11.战斗&信息展示 12.药水使用 13.副本传送 14.玩家死亡 15.超时断开

OpenHarmony 视图缩放组件—subsampling-scale-image-view

简介 深度缩放视图&#xff0c;图像显示&#xff0c;手势平移缩放双击等 效果图&#xff08;旋转、缩放、平移&#xff09; 下载安装 ohpm install ohos/subsampling-scale-image-view OpenHarmony ohpm 环境配置等更多内容&#xff0c;请参考如何安装 OpenHarmony ohpm 包 使…

Servlet第四篇【request对象常用方法、应用】

什么是HttpServletRequest HttpServletRequest对象代表客户端的请求&#xff0c;当客户端通过HTTP协议访问服务器时&#xff0c;HTTP请求头中的所有信息都封装在这个对象中&#xff0c;开发人员通过这个对象的方法&#xff0c;可以获得客户这些信息。 简单来说&#xff0c;要得…

mysql四种引擎区别

MySQL 提供了多种不同的数据库引擎&#xff0c;其中最常见的有 MyISAM、InnoDB、MEMORY 和 BLACKHOLE。这四个引擎分别有以下特点&#xff1a; 1. MyISAM MyISAM 是 MySQL 的默认引擎。它对于只有较少的修改、大量读取的应用场景具有良好的性能。它不支持事务处理&#xff0c;也…
最新文章