江南 CAS 功能 #485

Merged
KingChan merged 2 commits from KingChan/forgeplus:factory_develop into factory_develop 2026-06-04 10:17:14 +08:00
4 changed files with 194 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"