Class: Pindo::PgyerFeishuOAuthCLI
- Inherits:
-
Object
- Object
- Pindo::PgyerFeishuOAuthCLI
- Defined in:
- lib/pindo/client/pgyer_feishu_oauth_cli.rb
Instance Attribute Summary collapse
-
#access_token ⇒ Object
readonly
Returns the value of attribute access_token.
-
#expires_at ⇒ Object
readonly
Returns the value of attribute expires_at.
-
#username ⇒ Object
readonly
Returns the value of attribute username.
Instance Method Summary collapse
-
#authorize ⇒ Object
启动授权流程.
-
#initialize(client_id) ⇒ PgyerFeishuOAuthCLI
constructor
A new instance of PgyerFeishuOAuthCLI.
-
#login_pgyer_with_feishu(code: nil) ⇒ Object
使用code登录Pgyer, 并且Pgyer返回token.
-
#validate_pgyer_token(token = nil, expires_at = nil) ⇒ Object
验证Pgyer令牌.
Constructor Details
#initialize(client_id) ⇒ PgyerFeishuOAuthCLI
Returns a new instance of PgyerFeishuOAuthCLI.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/pindo/client/pgyer_feishu_oauth_cli.rb', line 20 def initialize(client_id) @client_id = client_id @feishu_auth_url = 'https://passport.feishu.cn/suite/passport/oauth/authorize?' # 保持原有的redirect_uri,飞书OAuth流程中仍使用这个URL # 前端UI会检测state=terminal_login并自动跳转到localhost:8899 @redirect_uri = 'https://pgyerapps.com/login' @pgyer_api_endpoint = 'https://api.pgyerapps.com/api/user/lark_qr_login' @state = 'terminal_login' @larkScopeList = [ 'task:task:write', 'task:section:write', 'task:custom_field:write', 'task:tasklist:write' ]; @access_token = nil @username = nil @expires_at = nil end |
Instance Attribute Details
#access_token ⇒ Object (readonly)
Returns the value of attribute access_token.
18 19 20 |
# File 'lib/pindo/client/pgyer_feishu_oauth_cli.rb', line 18 def access_token @access_token end |
#expires_at ⇒ Object (readonly)
Returns the value of attribute expires_at.
18 19 20 |
# File 'lib/pindo/client/pgyer_feishu_oauth_cli.rb', line 18 def expires_at @expires_at end |
#username ⇒ Object (readonly)
Returns the value of attribute username.
18 19 20 |
# File 'lib/pindo/client/pgyer_feishu_oauth_cli.rb', line 18 def username @username end |
Instance Method Details
#authorize ⇒ Object
启动授权流程
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/pindo/client/pgyer_feishu_oauth_cli.rb', line 44 def # 不再检查已存储的令牌,直接开始授权流程 = puts "正在打开浏览器进行飞书OAuth授权..." puts "授权URI: #{}" puts "注意:授权成功后,网页将自动跳转至本地http://localhost:8899" # 在浏览器中打开授权URL open_browser() # 启动本地服务器处理回调 code = start_callback_server # 如果自动获取失败,提示用户手动输入 if code.nil? puts "自动获取授权码失败,您可以手动输入:" puts "1. 授权码 (直接复制'code='后面的内容)" puts "2. 完整回调URL (例如: http://localhost:8899/?code=xxxx...)" print "> " input = STDIN.gets.chomp if input.start_with?("http") # 尝试从URL中提取code begin uri = URI(input) query_params = URI.decode_www_form(uri.query || '').to_h code = query_params['code'] if code puts "从URL中成功提取授权码" end rescue => e puts "无法从URL中提取授权码: #{e.}" end else # 将输入直接作为code code = input unless input.empty? end end if code puts "成功获取授权码!正在使用飞书身份登录Pgyer..." puts "code: #{code}" if login_pgyer_with_feishu(code:code) puts "Pgyer登录成功!" # 登录成功后,返回true,外部程序可以通过访问access_token属性获取token return true end return false else puts "授权失败" return false end end |
#login_pgyer_with_feishu(code: nil) ⇒ Object
使用code登录Pgyer, 并且Pgyer返回token
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/pindo/client/pgyer_feishu_oauth_cli.rb', line 125 def login_pgyer_with_feishu(code: nil) return false unless code # 构造请求体 body_params = { code: code, redirectUri: @redirect_uri, scope: @larkScopeList.join(' ') } puts "请求Pgyer API: #{@pgyer_api_endpoint}" puts "请求参数: #{body_params.to_json}" # 使用HttpClient发送请求 con = HttpClient.create_instance_with_proxy begin res = con.post do |req| req.url @pgyer_api_endpoint req.headers['Content-Type'] = 'application/json' req.body = body_params.to_json end puts "API响应状态码: #{res.status}" # 处理响应 result = nil if !res.body.nil? begin result = JSON.parse(res.body) # puts "解析后的响应: #{result.inspect}" if result['code'] == 200 && !result['data'].nil? && !result['data']['token'].nil? @access_token = result['data']['token'] @username = result['data']['username'] if result['data']['username'] # 设置token有效期为7天后 @expires_at = Time.now.to_i + 6 * 24 * 60 * 60 # 7天的秒数 return true else error_msg = result['meta'] && result['meta']['message'] ? result['meta']['message'] : '未知错误' puts "Pgyer登录失败: #{error_msg}" return false end rescue => e puts "解析响应失败: #{e.}" puts "原始响应: #{res.body[0..200]}" return false end else puts "请求返回空响应" return false end rescue => e puts "请求过程中出错: #{e.class} - #{e.}" return false end end |
#validate_pgyer_token(token = nil, expires_at = nil) ⇒ Object
验证Pgyer令牌
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/pindo/client/pgyer_feishu_oauth_cli.rb', line 99 def validate_pgyer_token(token = nil, expires_at = nil) token_to_check = token || @access_token expiration_time = expires_at || @expires_at # 首先检查token是否存在 return false unless token_to_check # 然后检查token是否过期 if expiration_time && Time.now.to_i > expiration_time puts "令牌已过期,需要重新登录" return false end # 最后验证token是否有效 uri = URI("https://www.pgyer.com/api/user/profile") request = Net::HTTP::Get.new(uri) request['Authorization'] = "Bearer #{token_to_check}" response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| http.request(request) end return response.code == '200' end |