diff --git a/app/controllers/oauth/jiangnan_cas_controller.rb b/app/controllers/oauth/jiangnan_cas_controller.rb new file mode 100644 index 000000000..80b685b70 --- /dev/null +++ b/app/controllers/oauth/jiangnan_cas_controller.rb @@ -0,0 +1,25 @@ +class Oauth::JiangnanCasController < Oauth::BaseController + def create + user, is_new_user = Oauth::CreateORFindJiangnanCasUserService.call(check_params) + successful_authentication(user) + render_ok + end + + def verify + render json: { + "code": 200, + "msg": "token验证成功", + "data": [{ + "code": "02020020250912000001", + "userName":"XXX", + "nickName":"sss", + "thirdPartySign": "02020020250912000001", + "originPlatform": "00", + "expireTime": "xxx"}] + } + end + + def check_params + params.permit(:token, :clientIp) + end +end \ No newline at end of file diff --git a/app/models/open_users/jiangnan_cas.rb b/app/models/open_users/jiangnan_cas.rb new file mode 100644 index 000000000..e7ea6ca87 --- /dev/null +++ b/app/models/open_users/jiangnan_cas.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + +class OpenUsers::JiangnanCas < OpenUser + def nickname + extra&.[]('userName') + end + + def en_type + 'jiangnan_cas' + end +end diff --git a/app/services/oauth/create_or_find_jiangnan_cas_user_service.rb b/app/services/oauth/create_or_find_jiangnan_cas_user_service.rb new file mode 100644 index 000000000..941cf7fc9 --- /dev/null +++ b/app/services/oauth/create_or_find_jiangnan_cas_user_service.rb @@ -0,0 +1,140 @@ +class Oauth::CreateORFindJiangnanCasUserService < ApplicationService + CONFIG = Rails.application.config_for(:configuration)['jiangnan_cas'] + def initialize(params) + @params = params + end + + def call + result = verify_token(@params[:token], @params[:clientI]) + + return [nil, false] unless result[:success] + sso_user = result[:user] + + open_user = OpenUsers::JiangnanCas.find_by(uid: sso_user[:code]) + if open_user.present? + open_user.update(extra: sso_user.to_json) + + return [open_user.user, false] + end + + user = build_user(sso_user) + + ActiveRecord::Base.transaction do + user.save! + user.create_user_extension! + + OpenUsers::JiangnanCas.create!( + uid: sso_user[:code], + user: user, + extra: sso_user.to_json + ) + end + + [user, true] + end + + private + def verify_token(token, client_ip) + raise 'jiangnan_cas 未配置' if CONFIG.blank? + uri = URI.parse(CONFIG["domain"] + CONFIG["verify_url"]) + http = Net::HTTP.new(uri.host, uri.port) + #http.use_ssl = true + + # 如果是自签名证书,可临时关闭验证(正式环境不建议) + #http.verify_mode = OpenSSL::SSL::VERIFY_NONE + + request = Net::HTTP::Post.new(uri.request_uri) + + # 请求头 + request['Content-Type'] = 'application/json' + request['en-token-sso-user'] = token + + # 请求体 + request.body = { + clientIp: client_ip + }.to_json + + response = http.request(request) + + parse_response(response) + rescue URI::InvalidURIError => e + error_result("SSO 地址格式错误", e) + rescue Net::OpenTimeout => e + error_result("SSO 连接超时", e) + rescue Net::ReadTimeout => e + error_result("SSO 响应超时", e) + rescue SocketError => e + error_result("SSO 域名或IP无法访问", e) + rescue OpenSSL::SSL::SSLError => e + error_result("SSO SSL证书异常", e) + rescue JSON::ParserError => e + error_result("SSO 返回数据不是合法JSON", e) + rescue StandardError => e + error_result("SSO 验证失败", e) + end + + + + def parse_response(response) + json = JSON.parse(response.body) + success = json['code'].to_i == 200 + user = json['data']&.first || {} + + { + success: success, + code: json['code'], + msg: json['msg'], + + # 原始返回 + data: json['data'] || [], + + # 直接可用的用户信息 + user: { + code: user['code'], + user_name: user['userName'], + nick_name: user['nickName'], + third_party_sign: user['thirdPartySign'], + origin_platform: user['originPlatform'], + expire_time: user['expireTime'] + }, + + # http状态码 + http_status: response.code.to_i + } + end + + def error_result(message, exception) + Rails.logger.error <<~LOG + [SSO VERIFY ERROR] + message: #{message} + error: #{exception.class} + detail: #{exception.message} + LOG + + { + success: false, + code: 500, + msg: "#{message}:#{exception.message}", + data: [], + user: nil + } + end + + + def build_user(sso_user) + nickname = + sso_user[:nick_name].presence || + sso_user[:user_name].presence || + @params[:comsys_name] + + User.new( + login: User.generate_login('J'), + type: 'User', + status: User::STATUS_ACTIVE, + nickname: nickname, + lastname: nickname + ) + end + + +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 46fd18e1d..c45dd49df 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,6 +25,8 @@ Rails.application.routes.draw do # get 'auth/qq/callback', to: 'oauth/qq#create' get 'auth/failure', to: 'oauth/base#auth_failure' get 'auth/cas/callback', to: 'oauth/cas#create' + get 'auth/jiangnan/callback', to: 'oauth/jiangnan_cas#create' + post 'auth/jiangnan/verify', to: 'oauth/jiangnan_cas#verify' get 'auth/acge/callback', to: "oauth/acge#create" get 'oauth_ci4s', to: "oauth/ci4s#oauth_url" get 'auth/ci4s/callback', to: "oauth/ci4s#create"