Ngx Slider reCAPTCHA is a customizable Angular library that provides a slider-based CAPTCHA component to help secure forms from spam and bot submissions. The library offers multiple configuration options that allow for detailed customization of appearance, behavior, and feedback.
- Easy Setup: Quickly integrates with Angular projects.
- Highly Configurable: Supports default, global, and instance-specific configurations.
- Extensible: Allows custom implementations for image retrieval and verification.
Install NgxSliderRecaptcha
using npm:
npm install ngx-slider-recaptcha --save
To start using NgxSliderRecaptcha
:
- Import
NgxSliderRecaptchaModule
in your app module and optionally configure it globally.
@NgModule({
imports: [
NgxSliderRecaptchaModule
]
})
export class AppModule {}
- Add
<ngx-slider-recaptcha></ngx-slider-recaptcha>
in your template:
<ngx-slider-recaptcha (onResolved)="onResolved($event)"></ngx-slider-recaptcha>
- Handle the verification event in your component:
export class AppComponent {
onResolved(event: VerificationResponse): void {
if (event.success) {
console.log('Verification successful');
} else {
console.log('Verification failed');
}
}
}
- Update angular.json for default slider images:
If you want to use the default slider images, add the following to your angular.json file under the assets section:
{
"glob": "**/*",
"input": "node_modules/ngx-slider-recaptcha/images",
"output": "/assets/images"
}
Ngx Slider reCAPTCHA
supports multiple configuration levels, making it flexible and easy to adapt to different use cases. The three main configuration levels are default, global, and instance-level configurations.
By default, Ngx Slider reCAPTCHA
uses predefined settings that are suitable for most use cases. These values are defined in the DEFAULT_SLIDER_RECAPTCHA_CONFIG
object:
export const DEFAULT_SLIDER_RECAPTCHA_CONFIG: NgxSliderRecaptchaConfig = {
width: 300,
height: 200,
puzzleSize: 42,
puzzleRadius: 9,
sliderContainerHeight: 40,
toleranceOffset: 5,
maxRetryAttempts: 3,
allowRefresh: false,
primaryColor: '#0083c1',
errorColor: '#c4161c',
successColor: '#52ccba',
textColor: '#4b4b4b',
sliderContainerBackgroundColor: '#f7f9fa',
sliderContainerBorderColor: '#e6e8eb',
borderRadius: 4,
loadingText: 'Loading...',
instructionText: 'Slide to complete the puzzle',
};
Property | Type | Default | Description |
---|---|---|---|
width |
number |
300 |
Width of the slider reCAPTCHA container in pixels. |
height |
number |
200 |
Height of the slider reCAPTCHA container in pixels. |
puzzleSize |
number |
40 |
Size of the puzzle piece in pixels. |
puzzleRadius |
number |
5 |
Radius of the puzzle piece. |
sliderContainerHeight |
number |
40 |
Height of the slider container. |
toleranceOffset |
number |
5 |
Allowable deviation for successful verification in pixels. |
maxRetryAttempts |
number |
3 |
Maximum number of retry attempts allowed for image retrieval. |
allowRefresh |
boolean |
false |
Determines if the slider reCAPTCHA can be refreshed by the user. |
primaryColor |
string |
"#0083c1" |
Primary color for the slider elements. |
errorColor |
string |
"#c4161c" |
Color indicating an error state. |
successColor |
string |
"#52ccba" |
Color indicating a success state. |
textColor |
string |
"#4b4b4b" |
Color of loading or instructional text. |
sliderContainerBackgroundColor |
string |
"#f7f9fa" |
Background color of the slider container. |
sliderContainerBorderColor |
string |
"#e6e8eb" |
Border color of the slider container. |
borderRadius |
number |
4 |
Border radius for the slider and container elements. |
loadingText |
string |
"Loading..." |
Message shown while loading. |
instructionText |
string |
"Slide to complete the puzzle" |
Text providing instructions to users. |
Global configuration is defined when the module is imported in your app. This configuration applies to all ngx-slider-recaptcha
instances throughout your application unless overridden at the instance level.
To set a global configuration:
@NgModule({
imports: [
NgxSliderRecaptchaModule.forRoot({
config: {
width: 320,
height: 160,
allowRefresh: true
}
})
]
})
export class AppModule {}
In addition to the global configuration, each instance of the ngx-slider-recaptcha
component can be configured individually using @Input()
properties. Instance-level configurations will override the global configuration.
Example of instance-level configuration in the template:
<ngx-slider-recaptcha
[config]="{
width: 300,
height: 140,
}"
(onResolved)="onResolved($event)"
></ngx-slider-recaptcha>
In this example, only the width and height are overridden for this particular instance, while other settings will inherit from the global or default configuration.
- Instance-Level:
@Input()
properties on each component instance. - Global-Level:
forRoot()
configuration in the app module. - Default-Level: If neither instance nor global configuration is provided.
You can extend NgxSliderRecaptchaImageService
by providing custom classes for image retrieval.
@Injectable({
providedIn: 'root'
})
export class DefaultNgxSliderRecaptchaImageService implements NgxSliderRecaptchaImageService {
getSliderImage(): Observable<string> {
return of(`assets/images/ngx-slider-recaptcha-${Math.floor(Math.random() * 4)}.jpg`);
}
}
To use a custom image retriever, implement the NgxSliderRecaptchaImageService
interface in your Angular service. There are three methods for retrieving images:
- Client-Side Retrieval (from assets)
- Server-Side Retrieval (from a backend, e.g., Spring Boot)
- External Image Retrieval (from a public API or external service)
If your slider images are stored locally (e.g., in the assets
folder), you can easily retrieve them by specifying their paths.
@Injectable({
providedIn: 'root'
})
export class CustomNgxSliderRecaptchaImageService implements NgxSliderRecaptchaImageService {
getSliderImage(): Observable<string> {
return of('assets/path/to/your/image.jpg'); // Relative path to your image
}
}
To dynamically fetch slider images from a server (e.g., a Spring Boot backend), you can serve images as Base64 strings or URLs.
Spring Boot Backend
@RestController
public class CaptchaController {
@GetMapping("/api/slider-recaptcha/slider-image")
public String getSliderImage() {
try {
byte[] imageBytes = Files.readAllBytes(Paths.get("path/to/your/captcha/image.jpg"));
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
return "data:image/jpeg;base64," + base64Image;
} catch (Exception e) {
e.printStackTrace();
return "Error encoding image";
}
}
}
Frontend (Angular)
@Injectable({
providedIn: 'root'
})
export class CustomNgxSliderRecaptchaImageService implements NgxSliderRecaptchaImageService {
constructor(private http: HttpClient) {}
getSliderImage(): Observable<string> {
return this.http.get<string>('/api/get-captcha-image').pipe(
catchError(() => of('data:image/jpeg;base64,...')) // Fallback image
);
}
}
@Injectable({
providedIn: 'root'
})
export class CustomNgxSliderRecaptchaImageService implements NgxSliderRecaptchaImageService {
getSliderImage(): Observable<string> {
const width = 280;
const height = 155;
const randomImageUrl = `https://picsum.photos/${width}/${height}?random=${Math.round(Math.random() * 1000)}`;
return of(randomImageUrl);
}
}
To use this custom retriever in the module:
@NgModule({
imports: [
NgxSliderRecaptchaModule.forRoot({
imageRetrievalService: CustomNgxSliderRecaptchaImageService
})
]
})
export class AppModule {}
You can extend NgxSliderRecaptchaVerificationService<E extends VerificationRequest, T extends VerificationResponse>
by providing custom classes for verification.
@Injectable({
providedIn: 'root'
})
export class DefaultNgxSliderRecaptchaVerificationService implements NgxSliderRecaptchaVerificationService<VerificationRequest, VerificationResponse> {
verify(verificationRequest: VerificationRequest): Observable<VerificationResponse> {
if (!verificationRequest?.sliderMovements?.length) {
return of({
success: false,
message: 'No slider movement detected. Please try again.'
});
}
const { sliderMovements, puzzleBlockPosition, puzzlePosition, toleranceOffset: offset } = verificationRequest;
const averageMovement = sliderMovements.reduce((sum, value) => sum + value, 0) / sliderMovements.length;
const movementDeviation = Math.sqrt(
sliderMovements.reduce((sum, value) => sum + Math.pow(value - averageMovement, 2), 0) / sliderMovements.length
);
const isVerified = movementDeviation !== 0;
const isSpliced = Math.abs(puzzleBlockPosition - puzzlePosition) < (offset ?? 0);
const response: VerificationResponse = {
success: isSpliced && isVerified,
message: isSpliced && isVerified ? 'Verification successful' : 'Verification failed',
};
return of(response);
}
}
To use a custom verifier, implement the NgxSliderRecaptchaVerificationService<E extends VerificationRequest, T extends VerificationResponse>
interface. The verification logic can be implemented either client-side or server-side.
For client-side verification, create a class that implements NgxSliderRecaptchaVerificationService<E extends VerificationRequest, T extends VerificationResponse>
. The verify()
method will handle the slider movements validation.
@Injectable({
providedIn: 'root'
})
export class CustomNgxSliderRecaptchaVerificationService implements NgxSliderRecaptchaVerificationService<VerificationRequest, VerificationResponse> {
verify(verificationRequest: VerificationRequest): Observable<VerificationResponse> {
//Custom logic
return of({ success: true, message: 'Verified with custom logic' });
}
}
For enhanced security, you can implement server-side verification to handle slider movements validation, providing further control over the process.
To make the verification process more secure, you can also implement encryption and decryption. Encrypt the verification request data before sending it from the client-side and decrypt it on the server-side before processing the verification. This ensures that sensitive data is protected during transmission and reduces the risk of tampering or unauthorized access.
Spring Boot Backend
@RestController
@RequestMapping("/api/slider-recaptcha")
public class CaptchaController {
@PostMapping("/verify")
public ResponseEntity<SliderRecaptchaVerificationResponse> verify(@RequestBody SliderRecaptchaVerificationRequest verificationRequest) {
if (ObjectUtils.isEmpty(verificationRequest)) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
double avg = verificationRequest.getSliderMovements().stream().mapToInt(Integer::intValue).average().orElse(0);
double standardDeviation = verificationRequest.getSliderMovements().stream()
.mapToDouble(data -> Math.pow(data - avg, 2))
.average()
.orElse(0.0);
boolean isSpliced = Math.abs(verificationRequest.getPuzzleBlockPosition() - verificationRequest.getPuzzlePosition()) < verificationRequest.getToleranceOffset();
boolean isVerified = isSpliced && standardDeviation != 0;
SliderRecaptchaVerificationResponse verificationResponse = SliderRecaptchaVerificationResponse.builder()
.success(isVerified)
.message(isVerified ? "Verification successful" : "Verification failed")
.secretKey(isVerified ? generateSecretKey() : null)
.build();
return ResponseEntity.ok(verificationResponse);
}
private String generateSecretKey() {
return "secretKey12345"; // Example logic for generating a secret key
}
}
Frontend (Angular)
@Injectable({
providedIn: 'root'
})
export class CustomNgxSliderRecaptchaVerificationService implements NgxSliderRecaptchaVerificationService<VerificationRequest, VerificationResponse> {
constructor(
private http: HttpClient,
) {
}
verify(verificationRequest: VerificationRequest): Observable<VerificationResponse> {
if (!verificationRequest?.sliderMovements?.length) {
return of({
success: false,
message: 'No slider movement detected. Please try again.'
});
}
return this.http.post<VerificationResponse>(
`${environment.baseUrl}/api/slider-recaptcha/verify`,
verificationRequest
).pipe(
tap((response) => {
console.log('Verification successful', response);
}),
catchError((err) => {
console.error('Verification failed', err);
return of({
success: false,
message: 'Verification failed due to an error.'
});
})
);
}
}
To use this custom verification in the module:
@NgModule({
imports: [
NgxSliderRecaptchaModule.forRoot({
verificationService: CustomNgxSliderRecaptchaVerificationService
})
]
})
export class AppModule {}
- Client-Side Image Retrieval: Fetch images from local assets by specifying the relative path.
- Server-Side Image Retrieval: Dynamically fetch images from a backend (e.g., Spring Boot) as Base64 or a URL.
- Client-Side Verification: Implement a simple slider verification logic in the frontend.
- Server-Side Verification: For enhanced security, implement slider verification on the backend to control the validation process more securely.
This project was inspired by SliderCaptcha by ArgoZhang. Special thanks to ArgoZhang for providing a foundational approach that influenced the development of this Angular library.
This library is distributed under the MIT License. See LICENSE for more information.