| @@ -118,6 +118,10 @@ gem 'deep_cloneable', '~> 3.0.0' | |||
| # oauth2 | |||
| gem 'omniauth', '~> 1.9.0' | |||
| gem 'omniauth-oauth2', '~> 1.6.0' | |||
| gem "omniauth-github" | |||
| gem "omniauth-rails_csrf_protection" | |||
| gem 'omniauth-gitee', '~> 1.0.0' | |||
| gem "omniauth-wechat-oauth2" | |||
| # global var | |||
| gem 'request_store' | |||
| @@ -11,7 +11,7 @@ module LoginHelper | |||
| def set_autologin_cookie(user) | |||
| token = Token.get_or_create_permanent_login_token(user, "autologin") | |||
| sync_user_token_to_trustie(user.login, token.value) | |||
| # sync_user_token_to_trustie(user.login, token.value) | |||
| Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}" | |||
| cookie_options = { | |||
| @@ -1,14 +1,21 @@ | |||
| module RegisterHelper | |||
| extend ActiveSupport::Concern | |||
| def autologin_register(username, email, password, platform= 'forge') | |||
| def autologin_register(username, email, password, platform = 'forge', phone = nil, nickname =nil, need_edit_info = false) | |||
| result = {message: nil, user: nil} | |||
| email = email.blank? ? "#{username}@example.org" : email | |||
| user = User.new(admin: false, login: username, mail: email, type: "User") | |||
| user.password = password | |||
| user.platform = platform | |||
| user.activate | |||
| user.phone = phone if phone.present? | |||
| user.nickname = nickname if nickname.present? | |||
| if need_edit_info | |||
| user.need_edit_info | |||
| else | |||
| user.activate | |||
| end | |||
| return unless user.valid? | |||
| interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) | |||
| @@ -36,7 +43,7 @@ module RegisterHelper | |||
| user.password = params[:password] | |||
| user.mail = params[:email] | |||
| if user.save! | |||
| if user.save! | |||
| sync_params = { | |||
| password: params[:password].to_s, | |||
| email: params[:email], | |||
| @@ -44,9 +51,9 @@ module RegisterHelper | |||
| new_name: params[:username], | |||
| source_id: 0 | |||
| } | |||
| interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params) | |||
| if interactor.success? | |||
| if interactor.success? | |||
| result[:user] = user | |||
| else | |||
| result[:message] = '用户同步Gitea失败!' | |||
| @@ -2,6 +2,7 @@ class Oauth::BaseController < ActionController::Base | |||
| include RenderHelper | |||
| include LoginHelper | |||
| include ControllerRescueHandler | |||
| include RegisterHelper | |||
| # include LaboratoryHelper | |||
| skip_before_action :verify_authenticity_token | |||
| @@ -22,7 +23,7 @@ class Oauth::BaseController < ActionController::Base | |||
| end | |||
| def auth_hash | |||
| Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") | |||
| # Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") | |||
| request.env['omniauth.auth'] | |||
| end | |||
| @@ -0,0 +1,65 @@ | |||
| class Oauth::CallbacksController < Oauth::BaseController | |||
| def create | |||
| process_callback | |||
| rescue Exception => e | |||
| tip_exception("授权失败") | |||
| end | |||
| private | |||
| def config_providers | |||
| config = Rails.application.config_for(:configuration) | |||
| config.dig("oauth").keys | |||
| end | |||
| # QQ: {"ret":0,"msg":"","is_lost":0,"nickname":"颜值不算太高","gender":"男","gender_type":1,"province":"","city":"","year":"2013","constellation":"","figureurl":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/30","figureurl_1":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/50","figureurl_2":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/100","figureurl_qq_1":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=40\u0026t=1568887757","figureurl_qq_2":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=100\u0026t=1568887757","figureurl_qq":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=140\u0026t=1568887757","figureurl_type":"1","is_yellow_vip":"0","vip":"0","yellow_vip_level":"0","level":"0","is_yellow_year_vip":"0"} | |||
| def process_callback | |||
| Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") | |||
| if auth_hash.blank? | |||
| redirect_to("/login") && return | |||
| end | |||
| new_user = false | |||
| platform = auth_hash[:provider] | |||
| uid = auth_hash[:uid] | |||
| mail = auth_hash.info.email || nil | |||
| nickname = ["gitee", "github"].include?(platform) ? auth_hash.info.name : auth_hash.info.nickname | |||
| open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid) | |||
| if open_user.present? && open_user.user.present? | |||
| successful_authentication(open_user.user) | |||
| else | |||
| if current_user.blank? || !current_user.logged? | |||
| has_user = User.find_by(mail: mail) | |||
| if has_user.present? | |||
| "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: has_user.id, uid: uid, extra: auth_hash.extra) | |||
| successful_authentication(has_user) | |||
| else | |||
| new_user = true | |||
| login = build_login_name(platform, auth_hash.info.nickname) | |||
| mail = "#{login}@example.org" if mail.blank? | |||
| reg_result = autologin_register(login, mail, "Ec#{login}2022#", platform, nil, nickname) | |||
| Rails.logger.info("[OAuth2] omniauth.auth [reg_result] #{reg_result} ") | |||
| if reg_result[:message].blank? | |||
| open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: reg_result[:user][:id], uid: uid, extra: auth_hash.extra) | |||
| successful_authentication(open_user.user) | |||
| else | |||
| tip_exception(reg_result.present? ? reg_result[:message] : "授权失败") | |||
| end | |||
| end | |||
| else | |||
| "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: login, extra: auth_hash.extra) | |||
| end | |||
| end | |||
| redirect_to root_path(new_user: new_user) | |||
| end | |||
| # gitee,github nickname=login,如果系统未占用保留原用户名 | |||
| def build_login_name(provider, nickname) | |||
| if ["gitee", "github"].include?(provider) && User.find_by(login: nickname).blank? | |||
| nickname | |||
| else | |||
| User.generate_user_login('p') | |||
| end | |||
| end | |||
| end | |||
| @@ -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::Gitee < OpenUser | |||
| def nickname | |||
| extra&.[]('nickname') | |||
| end | |||
| def en_type | |||
| 'gitee' | |||
| end | |||
| end | |||
| @@ -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::Github < OpenUser | |||
| def nickname | |||
| extra&.[]('name') | |||
| end | |||
| def en_type | |||
| 'github' | |||
| end | |||
| end | |||
| @@ -113,7 +113,7 @@ class User < Owner | |||
| # trustie: 来自Trustie平台 | |||
| # forge: 平台本身注册的用户 | |||
| # military: 军科的用户 | |||
| enumerize :platform, in: [:forge, :educoder, :trustie, :military], default: :forge, scope: :shallow | |||
| enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat], default: :forge, scope: :shallow | |||
| belongs_to :laboratory, optional: true | |||
| has_one :user_extension, dependent: :destroy | |||
| @@ -774,6 +774,15 @@ class User < Owner | |||
| login | |||
| end | |||
| # 生成数字账号 | |||
| CODES = %W(0 1 2 3 4 5 6 7 8 9) | |||
| def self.generate_user_login type | |||
| code = CODES.sample(8).join | |||
| code = type + code.to_s | |||
| return User.generate_user_login(type) if User.where(login: code).present? | |||
| code | |||
| end | |||
| def bind_open_user?(type) | |||
| case type | |||
| when 'wechat' then wechat_open_user.present? | |||
| @@ -1,21 +1,27 @@ | |||
| OmniAuth.config.add_camelization 'qq', 'QQ' | |||
| config = Rails.application.config_for(:configuration) | |||
| OmniAuth.config.add_camelization 'qq', 'QQ' if config.dig("oauth", "qq") | |||
| OmniAuth.config.add_camelization 'github', 'GitHub' if config.dig("oauth", "github") | |||
| OmniAuth.config.add_camelization 'gitee', 'Gitee' if config.dig("oauth", "gitee") | |||
| OmniAuth.config.add_camelization 'wechat', 'Wechat' if config.dig("oauth", "wechat") | |||
| OmniAuth.config.logger = Rails.logger | |||
| OmniAuth.config.before_request_phase = nil | |||
| OmniAuth.config.before_callback_phase = nil | |||
| OmniAuth.config.on_failure = Proc.new { |env| | |||
| OmniAuth::FailureEndpoint.new(env).redirect_to_failure | |||
| } | |||
| oauth_config = {} | |||
| begin | |||
| config = Rails.application.config_for(:configuration) | |||
| oauth_config = config.dig('oauth', 'qq') | |||
| raise 'oauth qq config missing' if oauth_config.blank? | |||
| rescue => ex | |||
| raise ex if Rails.env.production? | |||
| puts %Q{\033[33m [warning] qq oauth config or configuration.yml missing, | |||
| please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} | |||
| end | |||
| Rails.application.config.middleware.use OmniAuth::Builder do | |||
| provider :qq, oauth_config['appid'], oauth_config['secret'], { provider_ignores_state: true } | |||
| if config.dig("oauth", "qq") | |||
| provider :qq, config.dig("oauth", "qq", "appid"), config.dig("oauth", "github", "secret"), { provider_ignores_state: true } | |||
| end | |||
| if config.dig("oauth", "github").present? | |||
| provider :github, config.dig("oauth", "github", "appid"), config.dig("oauth", "github", "secret"), { provider_ignores_state: true, scope: "user:email" } | |||
| end | |||
| if config.dig("oauth", "gitee").present? | |||
| provider :gitee, config.dig("oauth", "gitee", "appid"), config.dig("oauth", "gitee", "secret"), { provider_ignores_state: true, scope: "user_info emails" } | |||
| end | |||
| if config.dig("oauth", "wechat").present? | |||
| provider :gitee, config.dig("oauth", "wechat", "appid"), config.dig("oauth", "wechat", "secret"), { provider_ignores_state: true, scope: "snsapi_login" } | |||
| end | |||
| end | |||
| @@ -0,0 +1,7 @@ | |||
| # frozen_string_literal: true | |||
| # Be sure to restart your server when you modify this file. | |||
| # Enable per-form CSRF tokens. | |||
| # Rails.application.config.action_controller.per_form_csrf_tokens = true | |||
| # Rails.application.config.action_controller.forgery_protection_origin_check = true | |||
| @@ -23,6 +23,7 @@ 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/:provider/callback', to: 'oauth/callbacks#create' | |||
| get 'oauth/bind', to: 'oauth/educoder#bind' | |||
| get 'oauth/register', to: 'oauth#register' | |||