class SessionsController < ApplicationController allow_unauthenticated_access only: %i[ new create ] rate_limit to: 10, within: 3.minutes, only: :create, with: -> { flash.now[:alert] = "操作过频,请稍后重试" render inertia: "sessions/New", props: { flash: flash.to_h } } def new render inertia: "sessions/New", props: { flash: flash.to_h } end def create if user = User.authenticate_by(params.permit(:email_address, :password)) start_new_session_for user # Send notification email for new login if enabled # if user.notify_on_new_login? && !from_familiar_device?(user) # SessionMailer.new_login_notification(user, request.remote_ip, request.user_agent).deliver_later # end redirect_to after_authentication_url else # For Inertia.js, we need to render the component with flash messages flash.now[:alert] = "账户或密码错误" render inertia: "sessions/New", props: { flash: flash.to_h } end end def destroy terminate_session redirect_to new_session_path, notice: "你已登出" end def index @sessions = current_user.sessions.order(updated_at: :desc) render inertia: "sessions/Index", props: { sessions: @sessions.as_json(methods: [ :is_current ]), flash: flash.to_h } end def show @session = current_user.sessions.find(params[:id]) render inertia: "sessions/Show", props: { session: @session.as_json(methods: [ :is_current ]), flash: flash.to_h } rescue ActiveRecord::RecordNotFound redirect_to sessions_path, alert: "Session not found." end def destroy_session @session = current_user.sessions.find(params[:id]) if @session.is_current? redirect_to sessions_path, alert: "你不能终止当前会话。" else @session.destroy redirect_to sessions_path, notice: "会话已终止。" end rescue ActiveRecord::RecordNotFound redirect_to sessions_path, alert: "会话未找到。" end def terminate_all current_user.sessions.where.not(id: current_session.id).destroy_all redirect_to sessions_path, notice: "所有其他会话已终止。" end def security render inertia: "sessions/Security", props: { security_settings: current_user.security_settings, flash: flash.to_h } end def update_security if current_user.update(security_params) redirect_to security_sessions_path, notice: "安全设置已更新。" else render inertia: "sessions/Security", props: { security_settings: current_user.security_settings, errors: current_user.errors, flash: flash.to_h } end end private def from_familiar_device?(user) # Check if this device has been used before by this user user.sessions.where(user_agent: request.user_agent, ip_address: request.remote_ip).exists? end def security_params params.require(:user).permit( :require_two_factor, :session_timeout_minutes, :notify_on_new_login, :max_sessions ) end end