【问题标题】:Correct way to integrate reCAPTCHA with Angular 4将 reCAPTCHA 与 Angular 4 集成的正确方法
【发布时间】:2018-07-25 16:41:56
【问题描述】:

我正在尝试将 Invisible reCAPTCHA 与我的 Angular 4 表单集成。

在组件的 TS 部分我有这样的功能:

onSubmit(token: string) {
    alert(token);
}

我的 HTML 看起来像这样(仅显示相关部分):

<form (ngSubmit)="onSubmit()" #myForm="ngForm">
    <button  type="submit" class="btn g-recaptcha" data-sitekey="mykey" data-callback="onSubmit">Submit</button>
</form>

单击该按钮时,我会收到提示令牌未定义的警报,或者收到如下错误消息:“无法联系 reCAPTCHA。请检查您的连接并重试。”不是真正的确定性 - 有时我会看到一种行为,有时会看到另一种行为。

我认为表单标签中的 (ngSubmit) 可能会干扰 reCAPTCHA。但是,如果我删除 (ngSubmit),则根本不会调用 onSubmit 函数...

整合这个的正确方法是什么?

对于 AngularJS here on StackOverflow 也有类似的问题,但我真的不知道如何将该解决方案适应 Angular 4。

【问题讨论】:

标签: angular recaptcha angular4-forms angular-forms invisible-recaptcha


【解决方案1】:

在component.html中:

<re-captcha (resolved)="resolved($event)" siteKey="enter key"></re-captcha>

组件.ts

export class SignupComponent implements OnInit {
  resolved(captchaResponse: string) {
    console.log(`Resolved captcha with response ${captchaResponse}:`);
}

首先在模块中加载这个

import { RecaptchaModule } from 'ng-recaptcha';
imports: [
    BrowserModule,
     RecaptchaModule.forRoot(),  
    // RecaptchaFormsModule,  
] 

在 index.html 中 加载

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

【讨论】:

  • 验证码响应似乎已加密。你知道我们如何解密它吗?
【解决方案2】:

ReCAPTCHA 可以在 Angular 中实现如下。请注意,此示例不包含所需的服务器端代码。

先决条件

包括reCAPTCHA api

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

声明验证码

ReCAPTCHA 变量可以在 Typescript 中声明如下:

declare var grecaptcha: any;

但是,为了获得更多类型支持,可以使用接口ReCAPTCHA

declare var grecaptcha: ReCAPTCHA;

ReCAPTCHA 接口 (v2) [recaptcha.ts]

import { ElementRef } from '@angular/core';

/**
 * Interface for Google's reCAPTCHA JavaScript API. 
 * 
 * Display API
 * @see {@link https://developers.google.com/recaptcha/docs/display}
 * 
 * Invisible API
 * @see {@link https://developers.google.com/recaptcha/docs/invisible}
 */
export interface ReCAPTCHA {

  /**
   * Programatically invoke the reCAPTCHA check. Used if the invisible reCAPTCHA is on a div 
   * instead of a button.
   * 
   * @param {string} opt_widget_id Optional widget ID, defaults to the first widget created if 
   *     unspecified.
   */
  execute(opt_widget_id?: string): void;

  /** 
   * Renders the container as a reCAPTCHA widget and returns the ID of the newly created widget.
   * 
   * @param {ElementRef|string} container The HTML element to render the reCAPTCHA widget.  Specify 
   *    either the ID of the container (string) or the DOM element itself. 
   * @param {Object} parameters An object containing parameters as key=value pairs, for example,
   *    {"sitekey": "your_site_key", "theme": "light"}.
   */
  render(container: ElementRef|string, parameters: {[key: string]: string}): void;

  /** 
   * Resets the reCAPTCHA widget.
   * 
   * @param {string} opt_widget_id Optional widget ID, defaults to the first widget created if 
   *     unspecified.
   */
  reset(opt_widget_id?: string): void;

  /** 
   * Gets the response for the reCAPTCHA widget. Returns a null if reCaptcha is not validated. 
   * 
   * @param {string} opt_widget_id Optional widget ID, defaults to the first widget created if 
   *     unspecified.
   */
  getResponse(opt_widget_id?: string): string;
}


ReCAPTCHA 角度服务 [recaptcha.service.ts]

import { Injectable, OnInit } from '@angular/core'
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'

export interface ReCAPTCHAResponse {
  success: boolean; 
  status_code: number,
  error_codes?: Array<string>;
}

const httpOptions = {
  headers: {'Content-Type': 'application/json'},
  observe: "body",
  responseType: "json",
  withCredentials: true
}


@Injectable()
export class ReCAPTCHAService {
  public constructor(private http: HttpClient) {}

  public verifyUserResponse(userResponseToken: string): Observable<ReCAPTCHAResponse> {
    return this.http.post<ReCAPTCHAResponse>('/auth/captcha', {'g-recaptcha-response': userResponseToken}, httpOptions).
      pipe(map( (resp: HttpResponse) => { ... resp.body }))
  } 
}


角度组件

import { Component, OnDestroy, OnInit } from '@angular/core'
import { ReCAPTCHA } from './recaptcha'
import { ReCAPTCHAResponse, ReCAPTCHAService } from './recaptcha.service'


declare var grecaptcha: ReCAPTCHA;
declare var window: any;

@Component ({
  moduleId: module.id,
  selector: 'create-account',
  templateUrl: 'create-account.component.html'
})
export class CreateAccountComponent implements OnDestroy, OnInit {

  public constructor(private recaptcha: ReCAPTCHAService) {}

  public ngOnInit(): void {
    // Export reCAPTCHACallback to global scope.
    window['reCAPTCHACallback'] = this.reCAPTCHACallback.bind(this);

    grecaptcha.render('create-account-captcha', {
      'sitekey': 'your-site-key',
      'size': 'invisible',        // Optional (see docs)
      'callback': 'reCAPTCHACallback'
    });
  }

  /**
   * Verify reCAPTCHA response on server. 
   */
  public reCAPTCHACallback(token: string) {
    if (token == null || token.length === 0) {
      grecaptcha.reset();
      // TODO: report that captcha was invalid
    } else {
      this.recaptcha.verifyUserResponse(token).subscribe(
        (r: ReCAPTCHAResponse) => {
          if (r.success) {
            // TODO: create the new user account
          } else {
            grecaptcha.reset();
            // TODO: report that captcha was invalid
          }
        },
        (error: any) => {
          // TODO: handle server error
        }
      })
  }
}

组件模板

<!-- Invisible reCAPTCHA dynamically rendered. -->
<div id='create-account-captcha' class="g-recaptcha"></div>

【讨论】:

  • 这很有帮助,我已经设法让所有不同的位工作,除了我收到错误“缺少输入响应”。我没有使用“隐形”选项。这需要不同的实现吗?
  • 好的,所以对于遇到此问题的任何其他人 - 它与后端(服务器端)请求有关。显然,谷歌希望 URL 如下:https://www.google.com/recaptcha/api/siteverify?secret=' + secret + '&amp;response=' + responseToken。除此之外,如果您不想安装 npm 包或编写指令,这是一个很好的答案并且很简单。
【解决方案3】:

这是我目前在 Angular 10 中使用的一个很棒的 reCAPTCHA npm 库。

npm i ng-recaptcha

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2017-09-15
    • 2019-06-09
    • 1970-01-01
    相关资源
    最近更新 更多