flutter开发实战-指纹、面容ID验证插件实现

news2024/9/20 14:42:36

flutter开发实战-指纹、面容ID验证插件实现
在iOS开发中,经常出现需要指纹、面容ID验证的功能。

指纹、面容ID是一种基于用生物识别技术,通过扫描用户的面部特征来验证用户身份。

一、效果图

在这里插入图片描述
在这里插入图片描述

二、iOS指纹、面容ID验证

在iOS中实现指纹、面容ID验证功能,步骤如下

2.1 info.plist配置

在info.plist中配置允许访问FACE ID权限

<key>NSFaceIDUsageDescription</key>
<string>允许设备访问Face ID</string>

2.2 引入LocalAuthentication

在代码中引入#import <LocalAuthentication/LocalAuthentication.h>

具体代码实现如下

SDAuthID.h

#import <Foundation/Foundation.h>
#import <LocalAuthentication/LocalAuthentication.h>

/**
 *  设备支持的生物验证方式
 */
typedef NS_ENUM(NSUInteger, SDAuthIDSupportType) {
    /**
     *  支持TouchID验证
     */
    SDAuthIDSupportTypeTouchID = 1,
    /**
     *  支持FaceID验证
     */
    SDAuthIDSupportTypeFaceID,
    /**
     *  不支持支持验证
     */
    SDAuthIDSupportTypeNone,
};

/**
 *  TouchID/FaceID 状态
 */
typedef NS_ENUM(NSUInteger, SDAuthIDState){
    
    /**
     *  当前设备不支持TouchID/FaceID
     */
    SDAuthIDStateNotSupport = 0,
    /**
     *  TouchID/FaceID 验证成功
     */
    SDAuthIDStateSuccess = 1,
    
    /**
     *  TouchID/FaceID 验证失败
     */
    SDAuthIDStateFail = 2,
    /**
     *  TouchID/FaceID 被用户手动取消
     */
    SDAuthIDStateUserCancel = 3,
    /**
     *  用户不使用TouchID/FaceID,选择手动输入密码
     */
    SDAuthIDStateInputPassword = 4,
    /**
     *  TouchID/FaceID 被系统取消 (如遇到来电,锁屏,按了Home键等)
     */
    SDAuthIDStateSystemCancel = 5,
    /**
     *  TouchID/FaceID 无法启动,因为用户没有设置密码
     */
    SDAuthIDStatePasswordNotSet = 6,
    /**
     *  TouchID/FaceID 无法启动,因为用户没有设置TouchID/FaceID
     */
    SDAuthIDStateTouchIDNotSet = 7,
    /**
     *  TouchID/FaceID 无效
     */
    SDAuthIDStateTouchIDNotAvailable = 8,
    /**
     *  TouchID/FaceID 被锁定(连续多次验证TouchID/FaceID失败,系统需要用户手动输入密码)
     */
    SDAuthIDStateTouchIDLockout = 9,
    /**
     *  当前软件被挂起并取消了授权 (如App进入了后台等)
     */
    SDAuthIDStateAppCancel = 10,
    /**
     *  当前软件被挂起并取消了授权 (LAContext对象无效)
     */
    SDAuthIDStateInvalidContext = 11,
    /**
     *  系统版本不支持TouchID/FaceID (必须高于iOS 8.0才能使用)
     */
    SDAuthIDStateVersionNotSupport = 12
};

typedef void (^SDAuthIDStateBlock)(SDAuthIDState state, NSError *error);

 SDAuthID : NSObject

+ (instancetype)sharedInstance;

/**
 判断设备支持哪种认证方式 TouchID & FaceID
 */
- (SDAuthIDSupportType)canSupportBiometrics;

/**
 * 启动TouchID/FaceID进行验证
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthIDWithDescription:(NSString *)description
           localizedFallbackTitle:(NSString *)localizedFallbackTitle
                            block:(SDAuthIDStateBlock)block;

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthTouchIDWithDescription:(NSString *)description
                localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                 block:(SDAuthIDStateBlock)block;

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthFaceIDWithDescription:(NSString *)description
               localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                block:(SDAuthIDStateBlock)block;


实现的代码

SDAuthID.m

#import "SDAuthID.h"

 SDAuthID

+ (instancetype)sharedInstance {
    static SDAuthID *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[SDAuthID alloc] init];
    });
    return instance;
}

/**
 * 启动TouchID/FaceID进行验证
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthIDWithDescription:(NSString *)description
           localizedFallbackTitle:(NSString *)localizedFallbackTitle
                            block:(SDAuthIDStateBlock)block {
    
    if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0) {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"系统版本不支持TouchID/FaceID (必须高于iOS 8.0才能使用)");
            block(SDAuthIDStateVersionNotSupport, nil);
        });
        return;
    }
    
    
    LAContext *context = [[LAContext alloc] init];
    // 认证失败提示信息,为 @"" 则不提示
    context.localizedFallbackTitle = localizedFallbackTitle;
    
    NSError *error = nil;
    
    // LAPolicyDeviceOwnerAuthenticationWithBiometrics: 用TouchID/FaceID验证
    // LAPolicyDeviceOwnerAuthentication: 用TouchID/FaceID或密码验证, 默认是错误两次或锁定后, 弹出输入密码界面
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
        [context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:description reply:^(BOOL success, NSError * _Nullable error) {
            
            if (success) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"TouchID/FaceID 验证成功");
                    block(SDAuthIDStateSuccess, error);
                });
            } else if(error){
                if ((iOS 11.0, *)) {
                    switch (error.code) {
                        case LAErrorAuthenticationFailed:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 验证失败");
                                block(SDAuthIDStateFail, error);
                            });
                            break;
                        }
                        case LAErrorUserCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被用户手动取消");
                                block(SDAuthIDStateUserCancel, error);
                            });
                        }
                            break;
                        case LAErrorUserFallback:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"用户不使用TouchID/FaceID,选择手动输入密码");
                                block(SDAuthIDStateInputPassword, error);
                            });
                        }
                            break;
                        case LAErrorSystemCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被系统取消 (如遇到来电,锁屏,按了Home键等)");
                                block(SDAuthIDStateSystemCancel, error);
                            });
                        }
                            break;
                        case LAErrorPasscodeNotSet:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无法启动,因为用户没有设置密码");
                                block(SDAuthIDStatePasswordNotSet, error);
                            });
                        }
                            break;
                        case LAErrorBiometryNotEnrolled:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无法启动,因为用户没有设置TouchID/FaceID");
                                block(SDAuthIDStateTouchIDNotSet, error);
                            });
                        }
                            break;
                        case LAErrorBiometryNotAvailable:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无效");
                                block(SDAuthIDStateTouchIDNotAvailable, error);
                            });
                        }
                            break;
                        case LAErrorBiometryLockout:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被锁定(连续多次验证TouchID/FaceID失败,系统需要用户手动输入密码)");
                                block(SDAuthIDStateTouchIDLockout, error);
                            });
                        }
                            break;
                        case LAErrorAppCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (如App进入了后台等)");
                                block(SDAuthIDStateAppCancel, error);
                            });
                        }
                            break;
                        case LAErrorInvalidContext:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (LAContext对象无效)");
                                block(SDAuthIDStateInvalidContext, error);
                            });
                        }
                            break;
                        default:
                            break;
                    }
                } else {
                    // iOS 11.0以下的版本只有 TouchID 认证
                    switch (error.code) {
                        case LAErrorAuthenticationFailed:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 验证失败");
                                block(SDAuthIDStateFail, error);
                            });
                            break;
                        }
                        case LAErrorUserCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被用户手动取消");
                                block(SDAuthIDStateUserCancel, error);
                            });
                        }
                            break;
                        case LAErrorUserFallback:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"用户不使用TouchID,选择手动输入密码");
                                block(SDAuthIDStateInputPassword, error);
                            });
                        }
                            break;
                        case LAErrorSystemCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等)");
                                block(SDAuthIDStateSystemCancel, error);
                            });
                        }
                            break;
                        case LAErrorPasscodeNotSet:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无法启动,因为用户没有设置密码");
                                block(SDAuthIDStatePasswordNotSet, error);
                            });
                        }
                            break;
                        case LAErrorTouchIDNotEnrolled:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无法启动,因为用户没有设置TouchID");
                                block(SDAuthIDStateTouchIDNotSet, error);
                            });
                        }
                            break;
                            //case :{
                        case LAErrorTouchIDNotAvailable:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无效");
                                block(SDAuthIDStateTouchIDNotAvailable, error);
                            });
                        }
                            break;
                        case LAErrorTouchIDLockout:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码)");
                                block(SDAuthIDStateTouchIDLockout, error);
                            });
                        }
                            break;
                        case LAErrorAppCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (如App进入了后台等)");
                                block(SDAuthIDStateAppCancel, error);
                            });
                        }
                            break;
                        case LAErrorInvalidContext:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (LAContext对象无效)");
                                block(SDAuthIDStateInvalidContext, error);
                            });
                        }
                            break;
                        default:
                            break;
                    }
                }
                
            }
        }];
        
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"当前设备不支持TouchID/FaceID");
            block(SDAuthIDStateNotSupport, error);
        });
    }
}


/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthTouchIDWithDescription:(NSString *)description
                localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                 block:(SDAuthIDStateBlock)block {
    [self showAuthIDWithDescription:description localizedFallbackTitle:localizedFallbackTitle block:block];
}

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthFaceIDWithDescription:(NSString *)description
               localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                block:(SDAuthIDStateBlock)block {
    [self showAuthIDWithDescription:description localizedFallbackTitle:localizedFallbackTitle block:block];
}

/**
 判断设备支持哪种认证方式 TouchID & FaceID
 */
- (SDAuthIDSupportType)canSupportBiometrics {
    LAContext *context = [[LAContext alloc] init];
    NSError *error;
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
        if (error != nil) {
            return SDAuthIDSupportTypeNone;
        }
        if ((iOS 11.0, *)) {
            return context.biometryType == LABiometryTypeTouchID ?  SDAuthIDSupportTypeTouchID:SDAuthIDSupportTypeFaceID ;
        }
    }
    return SDAuthIDSupportTypeNone;
}


具体使用方式如下;

需要在plist文件中添加 Privacy-Face ID Usage Description 属性
 <key>NSFaceIDUsageDescription</key>
 <string>允许设备访问Face ID</string>

 使用方式
 判断支持的类型
 SDAuthIDSupportType supportType = [[SDAuthID sharedInstance] canSupportBiometrics];
 SDAuthIDSupportType supportType = [[SDAuthID sharedInstance] canSupportBiometrics];
 
 NSString *description = @"";
 if(SDAuthIDSupportTypeFaceID == supportType){
     description = @"验证已有面容";
 } else if(SDAuthIDSupportTypeTouchID == supportType){
     description = @"通过Home键验证已有指纹";
 } else {
     description = @"不支持TouchID/FaceID";
 }
 
 [[SDAuthID sharedInstance] showAuthIDWithDescription:description localizedFallbackTitle:@"请输入密码" block:^(SDAuthIDState state, NSError *error) {
     if (state == SDAuthIDStateNotSupport) { // 不支持TouchID/FaceID
         NSLog(@"对不起,当前设备不支持指纹/面容ID");
     } else if(state == SDAuthIDStateFail) { // 认证失败
         NSLog(@"指纹/面容ID不正确,认证失败");
     } else if(state == SDAuthIDStateTouchIDLockout) {   // 多次错误,已被锁定
         NSLog(@"多次错误,指纹/面容ID已被锁定,请到手机解锁界面输入密码");
     } else if (state == SDAuthIDStateSuccess) { // TouchID/FaceID验证成功
         NSLog(@"认证成功!");
     }
 }];

三、实现flutter 调用指纹、面容ID插件

3.1、创建flutter plugin

创建flutter plugin,我使用的工具是Android studio。

配置如下内容:

  • Project name
  • Project location
  • Description
  • Project type: Plugin
  • Android language
  • iOS language
  • Platforms

如图所示

在这里插入图片描述

3.2、flutter调用代码实现

flutter 调用原生的代码,需要用到channel,这里使用Method channel

实现调用的platform_interface

import ‘flutter_authid_platform_interface.dart’;

/// An implementation of [FlutterAuthidPlatform] that uses method channels.
class MethodChannelFlutterAuthid extends FlutterAuthidPlatform {
  /// The method channel used to interact with the native platform.
  
  final methodChannel = const MethodChannel('flutter_authid');

  
  Future<String?> getPlatformVersion() async {
    final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
    return version;
  }

  
  Future<Map<dynamic, dynamic>?> getAuthIDSupportType() async {
    final result = await methodChannel.invokeMethod<Map<dynamic, dynamic>>('getAuthIDSupportType');
    return result;
  }

  
  Future<Map<dynamic, dynamic>?> authVerification({Map<dynamic, dynamic>? arguments}) async {
    final result = await methodChannel.invokeMethod<Map<dynamic, dynamic>>('authVerification', arguments);
    return result;
  }
}

调用的platform_interface的具体的类

import ‘flutter_authid_platform_interface.dart’;

class FlutterAuthid {
  Future<String?> getPlatformVersion() {
    return FlutterAuthidPlatform.instance.getPlatformVersion();
  }

  Future<Map<dynamic, dynamic>?> getAuthIDSupportType() {
    return FlutterAuthidPlatform.instance.getAuthIDSupportType();
  }

  ///Map<dynamic, dynamic> arguments = {};
  // arguments['faceAuthDesc'] = "验证已有面容";
  // arguments['touchAuthDesc'] = "通过Home键验证已有指纹";
  // arguments['noSupportAuthDesc'] = "不支持TouchID/FaceID";
  // arguments['fallbackTitle'] = "请输入密码";
  Future<Map<dynamic, dynamic>?> authVerification({Map<dynamic, dynamic>? arguments}) {
    return FlutterAuthidPlatform.instance.authVerification(arguments: arguments);
  }
}

/**
 注意:<key>NSFaceIDUsageDescription</key>
    <string>允许设备访问Face ID</string>
 */

3.3、插件的使用实例Example

在flutter插件的example中实现插件的调用,具体代码如下

class AuthPage extends StatefulWidget {
  const AuthPage({Key? key}) : super(key: key);

  
  State<AuthPage> createState() => _AuthPageState();
}

class _AuthPageState extends State<AuthPage> {
  final _flutterAuthidPlugin = FlutterAuthid();

  String authName = "";
  String authImage = "";
  String hintDescription = "";
  String supportType = "";

  
  void initState() {
    // TODO: implement initState
    super.initState();
    setupAuth();
  }

  Future<void> setupAuth() async {
    Map<dynamic, dynamic> result;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      result = await _flutterAuthidPlugin.getAuthIDSupportType() ?? {};
    } on PlatformException {
      result = {};
    }

    print("getAuthIDSupportType:$result");
    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      String type = result['supportType'].toString();
      supportType = type;
      if ("2" == type) {
        authImage = "auth_face@2x.png";
        authName = "面容";
      } else if ("1" == type) {
        authImage = "auth_finger@2x.png";
        authName = "指纹";
      }
      hintDescription = result['desc'];
    });

    authVerification();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Auth app'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Image(
              image: AssetImage("assets/images/$authImage"),
              width: 100.0,
              height: 100.0,
            ),
            SizedBox(height: 50.0,),
            Text(
              'SDAuthApp\n $hintDescription以进行登录',
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 18,
                color: Colors.black,
              ),
            ),
            SizedBox(height: 50.0,),
            TextButton(
              onPressed: () {
                authVerification();
              },
              child: Text(
                '点击验证$authName',
                style: TextStyle(
                  fontSize: 17,
                  color: Colors.black,
                ),
              ),
            )
          ],
        ),
      ),
    );
  }

  // 点击唤起指纹、面容ID验证
  Future<void> authVerification() async {
    Map<dynamic, dynamic> arguments = {};
    arguments['faceAuthDesc'] = "验证已有面容";
    arguments['touchAuthDesc'] = "通过Home键验证已有指纹";
    arguments['noSupportAuthDesc'] = "不支持TouchID/FaceID";
    arguments['fallbackTitle'] = "请输入密码";

    Map<dynamic, dynamic> result;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      result =
          await _flutterAuthidPlugin.authVerification(arguments: arguments) ??
              {};
    } on PlatformException {
      result = {};
    }

    print("authVerification:$result");
  }
}

四、小结

flutter开发实战-指纹、面容ID验证插件实现,主要iOS开发中的指纹、面容ID验证功能,通过flutter的插件实现调用原生的插件。

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/736672.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一同感受C++模版的所带来的魅力

文章目录 一、泛型编程思想二、函数模版1、函数模板概念2、函数模板格式3、函数模板的原理4、函数模板的实例化5、模板参数的匹配原则 三、类模版1、类模板的定义格式2、类模板的实例化 四、总结与提炼 一、泛型编程思想 首先我们来看一下下面这三个函数&#xff0c;如果学习过…

磁盘与文件系统管理

磁盘结构及分区表示 硬盘 Hard Disk Drive &#xff0c;简称 HDD 是计算机常用的存储设备之一。 1 磁盘基础 1.1 硬盘的结构 1.1.1 数据结构 ①扇区&#xff1a;磁盘上的每个磁道被等分为若干个弧段,这些弧段便是硬盘的扇区(Sector)。硬盘的第一个扇区&#xff0c;叫做引导…

【mysql】-【锁】

文章目录 概述MySQL并发事务访问相同记录读-读情况写-写情况读-写或写-读情况并发问题的解决方案 锁的不同角度分类 概述 事务的隔离性由这章讲述的锁来实现。 MySQL并发事务访问相同记录 并发事务访问相同记录的情况大致可以划分为3种: 读-读情况 读-读情况&#xff0c;…

使用vite创建vue3的Cesium基础项目

使用vite创建vue3的Cesium基础项目 使用vite创建vue3项目&#xff1a;可以参考官方文档Vite官方中文文档 1.1 在指定文件夹路径下使用npm&#xff08;前提是已经安装好了node&#xff09;&#xff1a; bash npm create vitelatest 1.2 cd到创建的项目文件夹&#xff1a; bash c…

符号化的正确姿势

GUI方式 将 .ips crash report 文件拖放到 Xcode > Window > Devices and Simulators > View Device Logs中, 然后导出 .crash 符号化文件. 使用条件: crash report 对应的 Archive 包是在本机构建的 symbolicatecrash symbolicatecrash 是一个 exec (可执行文件), …

常见的BUG---1、虚拟机启动之后,突然发现没有ens33网卡

1、问题描述 今天一开启虚拟机&#xff0c;发现用XShell连接不上我的一台虚拟机&#xff0c;其他虚拟机是正常可以连接的&#xff0c;我稍微看了一下XShell的配置和Windows中的映射文件&#xff08;hosts&#xff09;&#xff0c;都没有啥问题&#xff0c;然后我就知道应该是虚…

javap反编译字节码文件

javap -v main.class{public static void main(String[] args) {int a10;int b10;int cab;return;} } Classfile /F:/myCode/java/jvm/0710_demo01/untitled/target/classes/org/example/main.classLast modified 2023年7月10日; size 447 bytesMD5 checksum 675a0d673d66326b…

基于SpringBoot+Vue的影城管理系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

服务器中了malox勒索病毒的解决办法流程与解密方案

随着网络科技技术的不断发展&#xff0c;越来越多的企业开始重视数据&#xff0c;数字化办公已经成为众多企业工作的常态&#xff0c;因此数据的安全性受到了额外重视。但网络科技技术的发展不仅方便了我们的工作&#xff0c;也给企业的数据安全带来了很大威胁。近期&#xff0…

基于SpringBoot+Vue的疫情网课管理系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

【H5】Promise的用法

系列文章 C#底层库–记录日志帮助类 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/124187709 文章目录 系列文章前言一、技术介绍二、项目源码2.1 Promise的状态2.2 Promise的结果2.3 Promise的then方法参数2.4 Promise的then方法获取数据 三、效果…

5G时代的材料新宠——液晶高分子聚合物

液晶高分子聚合物时80年代初期发展起来的一种新型高性能工程塑料&#xff0c;英文名为&#xff1a;Liquid Crystal Polymer 简称为LCP。 聚合方法以熔融缩聚为主&#xff0c;全芳香族LCP多辅以固相缩聚以制得高分子量产品。非全芳香族LCP常采用一步或二步熔融聚合制取产品。近年…

jwt介绍与使用

0.介绍 JWT(JSON Web Token)是一种开放标准&#xff0c;用于在双方之间安全地传输编码为 JSON 对象的信息。它是一个紧凑和自包含的方式&#xff0c;用于作为 JSON 对象在各方之间安全地传输信息。此信息可以进行验证和信任&#xff0c;因为它是经过数字签名的。JWT 可以使用机…

Python零基础入门(七)——Python中的选择和循环语句

系列文章目录 个人简介&#xff1a;机电专业在读研究生&#xff0c;CSDN内容合伙人&#xff0c;博主个人首页 Python入门专栏&#xff1a;《Python入门》欢迎阅读&#xff0c;一起进步&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; 码字不易&#xff0c;如果觉得文章不…

大学英语四新视野 课后习题+答案翻译 Unit1~Unit8

Unit 1 Text A: Words in use 2022年6月16日 20:57 1 As the gender barriers crumbled, the number of women working as lawyers, doctors, or bankers began to increase significantly from the mid-20th century. 随着性别障碍的消除&#xff0c;从20世纪中期开始&am…

C语言陷阱——无符号数和有符号数的大小比较

C语言易错知识点——无符号数和有符号数的大小比较 我们来看两串代码 代码一&#xff1a; #include<stdio.h>int main() {int a -1;if (a > sizeof(int)){printf(">\n");}else{printf("<\n");}return 0; }代码二&#xff1a; #include…

学生用啥台灯最好?适合暑假学习的台灯推荐

孩子们终于迎来了他们的暑假&#xff0c;肯定不少孩子都已经计划好每天该玩什么游戏&#xff0c;该看什么电视了吧。这也是最让家长们头疼的一段时间&#xff0c;不仅每天要监督他们不要玩太久电子产品&#xff0c;花时间学习之外&#xff0c;还要担心他们视力健康。说到学习&a…

C++图形开发(11):小球碰到方块的判定

文章目录 1.有哪些情况&#xff1f;1.1 小球在方块左侧1.2 小球在方块上面1.3 小球在方块右侧 2.解决 1.有哪些情况&#xff1f; 今天来实现下小球碰到方块的判定 那么我们首先要明确的就是在什么时候&#xff0c;小球会碰到方块&#xff1f; 1.1 小球在方块左侧 第一个就是…

介绍Unity3D 游戏实战开发之英雄联盟

本次游戏项目为类dota游戏中的经典之作《英雄联盟》&#xff0c;向经典致敬。通过本次课程&#xff0c;你会学到网游开发模式、C#服务器开发、协议定制、Unity5.0新特性开发、UGUI应用、同步方案、解决问题思路、各种扩展工具的开发………&#xff01; 演示地址&#xff1a; w…