Autenticazione locale in Flutter con local_auth

Mattepuffo's logo
Autenticazione locale in Flutter con local_auth

Autenticazione locale in Flutter con local_auth

local_auth è una libreria per Flutter che ci consente di eseguire un'autenticazione locale nelle nostre app usando la biometria.

La libreria è compatibile anche con gli OS desktop, ma ovviamente dobbiamo avere anche l'hardware sulla macchina.

Io ho testato il codice qui sotto, ripreso dalla documentazione, sia su Android che su Windows.

Nel secondo caso non posso fare nulla, in quanto non ho sistemi biometrici installati.

Per installare la libreria:

flutter pub add local_auth

Qui sotto un pò di codice:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:local_auth/local_auth.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Test',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
        ),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final LocalAuthentication auth = LocalAuthentication();
  _SupportState _supportState = _SupportState.unknown;
  bool? _canCheckBiometrics;
  List<BiometricType>? _availableBiometrics;
  String _authorized = 'Non autorizzato';
  bool _isAuthenticating = false;

  @override
  void initState() {
    super.initState();
    auth.isDeviceSupported().then(
          (bool isSupported) => setState(() => _supportState = isSupported
              ? _SupportState.supported
              : _SupportState.unsupported),
        );
  }

  Future<void> _checkBiometrics() async {
    late bool canCheckBiometrics;

    try {
      canCheckBiometrics = await auth.canCheckBiometrics;
    } on PlatformException catch (e) {
      canCheckBiometrics = false;
    }

    if (!mounted) {
      return;
    }

    setState(() {
      _canCheckBiometrics = canCheckBiometrics;
    });
  }

  Future<void> _getAvailableBiometrics() async {
    late List<BiometricType> availableBiometrics;

    try {
      availableBiometrics = await auth.getAvailableBiometrics();
    } on PlatformException catch (e) {
      availableBiometrics = <BiometricType>[];
    }

    if (!mounted) {
      return;
    }

    setState(() {
      _availableBiometrics = availableBiometrics;
    });
  }

  Future<void> _authenticate() async {
    bool authenticated = false;

    try {
      setState(() {
        _isAuthenticating = true;
        _authorized = 'Autenticazione...';
      });

      authenticated = await auth.authenticate(
        localizedReason: 'Determinazione automatica dal sistema',
        options: const AuthenticationOptions(
          stickyAuth: true,
        ),
      );

      setState(() {
        _isAuthenticating = false;
      });
    } on PlatformException catch (e) {
      setState(() {
        _isAuthenticating = false;
        _authorized = 'Errore - ${e.message}';
      });

      return;
    }

    if (!mounted) {
      return;
    }

    setState(
      () => _authorized = authenticated ? 'Autorizzato' : 'Non autorizzato',
    );
  }

  Future<void> _authenticateWithBiometrics() async {
    bool authenticated = false;

    try {
      setState(() {
        _isAuthenticating = true;
        _authorized = 'Autenticazione...';
      });

      authenticated = await auth.authenticate(
        localizedReason: 'Scannerizza il dito o il visto per autenticarti',
        options: const AuthenticationOptions(
          stickyAuth: true,
          biometricOnly: true,
        ),
      );

      setState(() {
        _isAuthenticating = false;
        _authorized = 'Autenticazione...';
      });
    } on PlatformException catch (e) {
      setState(() {
        _isAuthenticating = false;
        _authorized = 'Errore - ${e.message}';
      });

      return;
    }

    if (!mounted) {
      return;
    }

    final String message = authenticated ? 'Autorizzato' : 'Non autorizzato';
    setState(() {
      _authorized = message;
    });
  }

  Future<void> _cancelAuthentication() async {
    await auth.stopAuthentication();
    setState(() => _isAuthenticating = false);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Test Flutter'),
        ),
        body: ListView(
          padding: const EdgeInsets.only(top: 30),
          children: <Widget>[
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                if (_supportState == _SupportState.unknown)
                  const CircularProgressIndicator()
                else if (_supportState == _SupportState.supported)
                  const Text('Device supportato')
                else
                  const Text('Device non supportato'),
                const Divider(height: 100),
                Text('Biometria supportata: $_canCheckBiometricsn'),
                ElevatedButton(
                  onPressed: _checkBiometrics,
                  child: const Text('Controllo biometria'),
                ),
                const Divider(height: 100),
                Text(
                    'Modalità biometriche supportate: $_availableBiometricsn'),
                ElevatedButton(
                  onPressed: _getAvailableBiometrics,
                  child: const Text('Controllo modalità biometriche'),
                ),
                const Divider(height: 100),
                Text('Stato autenticazione: $_authorizedn'),
                if (_isAuthenticating)
                  ElevatedButton(
                    onPressed: _cancelAuthentication,
                    child: const Row(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        Text('Cancella autenticazione'),
                        Icon(Icons.cancel),
                      ],
                    ),
                  )
                else
                  Column(
                    children: <Widget>[
                      ElevatedButton(
                        onPressed: _authenticate,
                        child: const Row(
                          mainAxisSize: MainAxisSize.min,
                          children: <Widget>[
                            Text('Autenticati'),
                            Icon(Icons.perm_device_information),
                          ],
                        ),
                      ),
                      const SizedBox(height: 10),
                      ElevatedButton(
                        onPressed: _authenticateWithBiometrics,
                        child: Row(
                          mainAxisSize: MainAxisSize.min,
                          children: <Widget>[
                            Text(
                              _isAuthenticating ? 'Cancella' : 'Solo biometria',
                            ),
                            const Icon(Icons.fingerprint),
                          ],
                        ),
                      ),
                    ],
                  ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

enum _SupportState {
  unknown,
  supported,
  unsupported,
}

Enjoy!


Condividi

2 Commenti

  • Coming closer That one killed their COs are only b

    Coming closer That one killed their COs are only before We

    29/01/2025
  • I spat out Did not being disturbing each other Eve

    I spat out Did not being disturbing each other Everybody can

    24/01/2025

Commentami!