当前位置: 首页 > 科技观察

实现web端指纹登录

时间:2023-03-23 09:52:34 科技观察

本文转载自微信公众号《魔法程序员k》,作者魔法程序员k。转载本文请联系大神程序员K公众号。前言现在越来越多的笔记本电脑内置了指纹识别功能,用于从锁屏界面快速进入桌面,部分客户端软件也支持通过指纹进行用户身份认证。前几天在想既然客户端软件可以调用指纹仪,那么web端应该也可以调用。几经周折,终于实现了这个功能,并应用到了自己的开源项目中。本文将与大家分享我的实现思路和过程。欢迎有兴趣的开发者阅读本文。实现思路浏览器提供了WebAuthenticationAPI,我们可以通过调用用户指纹设备来实现用户信息认证。最终实现效果视频如下:Web端指纹登录的实现首先我们需要获取服务器返回的用户凭据进行指纹注册,然后将用户凭据传递给指纹设备激活指纹认证系统。认证通过后,回调函数会返回设备id和客户端信息。我们需要将这些信息保存在服务器上,以便后面调用指纹设备验证用户身份,从而实现登录。接下来我们总结一下注册指纹的过程,如下:用户通过其他方式登录网站成功后,服务器返回用户凭据,并将用户凭据保存在本地,以检测客户端是否有指纹设备。返回的用户凭据和用户信息被传递给指纹注册功能,以创建成功的指纹认证。回调函数返回设备id和客户端信息,并将设备id保存在本地。将设备id和客户端信息发送到服务器进行存储。到指定的用户数据。注意:登记指纹仅适用于使用https连接或本地主机的网站。指纹认证用户在本站授权指纹登录后,会在本地保存用户凭证和设备id。当用户进入我们的网站时,会从本地获取这两条数据,提示是否需要通过指纹登录系统,同意后,将设备id和用户凭证传递给指纹设备,并调用系统的指纹认证。认证通过后,调用登录接口获取用户信息。接下来我们总结一下指纹认证的流程,如下:从本地获取用户凭证和设备id检测客户端是否有指纹设备如果存在,则将用户凭证和设备id传给指纹认证函数进行验证验证成功,调用登录接口获取用户信息注意:指纹验证只能在使用https连接或localhost的网站上使用。在上一章的实现过程中,我们已经明确了指纹登录的具体实现思路。接下来我们看一下具体的实现过程和代码。服务端实现首先,我们需要在服务端写3个接口:获取TouchID、注册TouchID、指纹登录获取TouchID该接口用于判断登录用户是否在本网站注册了指纹,如果是,返回TouchID给客户端,方便用户下次登录。controller层代码如下@ApiOperation(value="GetTouchID",notes="通过userid获取指纹登录所需凭证")@CrossOrigin()@RequestMapping(value="/getTouchID",method=RequestMethod.POST)publicResultVOgetTouchID(@ApiParam(name="incominguserId",required=true)@Valid@RequestBodyGetTouchIdDtotouchIdDto,@RequestHeader(value="token")Stringtoken){JSONObjectresult=userService.getTouchID(JwtUtil.getUserId(token)));if(result.getEnum(ResultEnum.class,"code").getCode()==0){//touchId获取成功returnResultVOUtil.success(result.getString("touchId"));}//返回错误信息returnResultVOUtil.error(result.getEnum(ResultEnum.class,"code").getCode(),result.getEnum(ResultEnum.class,"code").getMessage());}该接口的具体实现代码如下//GetTouchID@OverridepublicJSONObjectgetTouchID(StringuserId){JSONObjectreturnResult=newJSONObject();//根据当前用户从数据库中查询touchIdidUseruser=userMapper.getTouchId(userId);StringtouchId=user.getTouchId();if(touchId!=null){//吨ouchId存在returnResult.put("code",ResultEnum.GET_TOUCHID_SUCCESS);returnResult.put("touchId",touchId);returnreturnResult;}//touchId不存在returnResult.put("code",ResultEnum.GET_TOUCHID_ERR);returnreturnResult;}RegisterTouchID该接口用于接收客户端指纹设备返回的TouchID和客户端信息,并将获取到的信息保存到数据库中的指定用户controller层代码如下@ApiOperation(value="RegisterTouchID",notes="保存客户端返回的touchid等信息")@CrossOrigin()@RequestMapping(value="/registeredTouchID",method=RequestMethod.POST)publicResultVOregisteredTouchID(@ApiParam(name="incominguserId",required=true)@Valid@RequestBodySetTouchIdDtotouchIdDto,@RequestHeader(value="token")Stringtoken){JSONObjectresult=userService.registeredTouchID(touchIdDto.getTouchId(),touchIdDto.getClientDataJson(),JwtUtil.getUserId(token));if(result.getEnum(ResultEnum.class,"code").getCode()==0){//touchId获取成功returnResultVOUtil.success(result.getString("data"));}//返回错误信息returnResultVOUtil.error(result.getEnum(ResultEnum.class,"code").getCode(),result.getEnum(ResultEnum.class,"code").getMessage());}接口具体实现代码如下//RegisterTouchID@OverridepublicJSONObjectregisteredTouchID(StringtouchId,StringclientDataJson,StringuserId){JSONObjectresult=newJSONObject();Userrow=newUser();row.setTouchId(touchId);row.setClientDataJson(clientDataJson);row.setUserId(userId);//根据userId更新touchId和客户端信息intupdateResult=userMapper.updateTouchId(row);if(updateResult>0){result.put("code",ResultEnum.SET_TOUCHED_SUCCESS);result.put("data","touch_id设置成功");returnresult;}result.put("code",ResultEnum.SET_TOUCHED_ERR);returnresult;}指纹login该接口接收客户端发送的用户凭证和touchId,然后与数据库中的数据进行校验,返回用户信息controller层代码如下@ApiOperation(value="指纹登录",notes="通过touchId和用户凭据登录系统")@CrossOrigin()@RequestMapping(value="/touchIdLogin",method=RequestMethod.POST)publicResultVOtouchIdLogin(@ApiParam(name="传入的TouchID和用户凭证",required=true)@Valid@RequestBodyTouchIDLoginDtotouchIDLogin){JSONObjectresult=userService.touchIdLogin(touchIDLogin.getTouchId(),touchIDLogin.getCertificate());returnLoginUtil.getLoginResult(result);}该接口的具体实现代码如下setUuid(证书);用户用户=用户映射器。selectUserForTouchId(row);StringuserName=user.getUserName();StringuserId=user.getUserId();//用户名为null时,返回错误信息if(userName==null){//指纹认证失败returnResult。put("code",ResultEnum.TOUCHID_LOGIN_ERR);returnreturnResult;}//指纹认证成功,返回用户信息给客户端//...这里代码省略,根据需要返回用户信息即可...//返回结果.put("code",ResultEnum.LOGIN_SUCCESS);returnreturnResult;}实现前端部分,前端需要结合现有的登录逻辑和指纹认证。我们需要实现两个功能:指纹注册和指纹登录对于指纹注册的功能,我们需要接收三个参数:用户名、用户id、用户凭证。我们需要这三个参数来调用指纹设备生成指纹。具体实现代码如下:touchIDRegistered:asyncfunction(userName:string,userId:string,certificate:string){//验证设备是否支持touchIDconsthasTouchID=awaitPublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();if(hasTouchID&&window.confirm("已经被检测到您的设备支持指纹登录,是否启用?")){//更新注册凭证this.touchIDOptions.publicKey.challenge=this.base64ToArrayBuffer(certificate);//更新用户名,用户idthis.touchIDOptions.publicKey.user.name=用户名;this.touchIDOptions.publicKey.user.displayName=用户名;this.touchIDOptions。publicKey.user.id=this.base64ToArrayBuffer(userId);//调用指纹设备创建指纹constpublicKeyCredential=awaitnavigator.credentials.create(this.touchIDOptions);if(publicKeyCredential&&"rawId"inpublicKeyCredential){//将rowId转换为base64constrawId=publicKeyCredential["rawId"];consttouchId=this.arrayBufferToBase64(rawId);constresponse=publicKeyCredential["response"];//获取客户端信息constclientDataJSON=this.arrayBufferToString(response["clientDataJSON"]);//调用注册的TouchID接口this.$api.touchIdLogingAPI.registeredTouchID({touchId:touchId,clientDataJson:clientDataJSON}).then((res:responseDataType)=>{if(res.code===0){//保存指纹登录的touchIdlocalStorage.setItem("touchId",touchId);return;}alert(res.msg);});}}}在上面function创建指纹时,使用一个对象,必须传递该对象才能创建指纹。其定义及各参数解释如下:consttouchIDOptions={publicKey:{rp:{name:"chat-system"},//网站信息user:{name:"",//用户名id:"",//用户id(ArrayBuffer)displayName:""//用户名},pubKeyCredParams:[{type:"public-key",alg:-7//Acceptedalgorithm}],challenge:"",//证书(touchIDOptions)authenticatorSelection:{authenticatorAttachment:"platform"}}}因为在touchIDOptions中,有些参数需要ArrayBuffer类型,我们数据库中保存的数据是base64格式的,所以需要实现base64和ArrayBuffer相互转换的功能.实现代码如下:base64ToArrayBuffer:function(base64:string){constbinaryString=window.atob(base64);constlen=binaryString.length;constbytes=newUint8Ar射线(len);for(leti=0;i{if(res.code==0){//store当前用户信息localStorage.setItem("token",res.data.token);localStorage.setItem("refreshToken",res.data.refreshToken);localStorage.setItem("profilePicture",res.data.avatarSrc);localStorage.setItem("userID",res.data.userID);localStorage.setItem("用户名",res.data.username);constcertificate=res.data.certificate;localStorage.setItem("certificate",certificate);//跳转消息组件this.$router.push({name:"message"});return;}//切回登录界面this.isLoginStatus=loginStatusEnum.NOT_LOGGED_IN;alert(res.msg);});}}注:注册新指纹后,旧的TouchID失效,只能通过新的Touch登录ID,否则系统无法激活指纹设备,会报错:认证有问题。整合已有的登录逻辑登录进行整合。调用指纹注册当用户使用用户名、密码或第三方平台授权成功登录后,我们调用指纹注册函数提示用户是否对网站进行授权。实现代码如下:authLogin:function(state:string,code:string,platform:string){this.$api.authLoginAPI.authorizeLogin({state:state,code:code,platform:platform}).then(async(res:responseDataType)=>{if(res.code==0){//...授权登录成功,其他代码省略...////保存指纹登录的用户凭证constcertificate=res.data.certificate;localStorage.setItem("certificate",certificate);//验证设备是否支持touchIDconsthasTouchID=awaitPublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();if(hasTouchID){//...其他代码省略...////获取TouchID,判断用户是否授权本站指纹登录$api.touchIdLogingAPI.getTouchID({userId:userId}).then(async(res:responseDataType)=>{if(res.code!==0){//touchId不存在,询问用户是否注册touchIdawaitthis.touchIDRegistered(username,userId,certificate);}//保存touchidlocalStorage.setItem("touchId",res.data);//跳转消息组件awaitthis.$router.push({name:"message"});});return;}//设备不支持touchID,直接跳转到消息组件awaitthis.$router.push({名称:“消息”});return;}//登录失败,切换回登录界面this.isLoginStatus=loginStatusEnum.NOT_LOGGED_IN;alert(res.msg);});}最终效果如下:每次第三方平台授权登录当前用户是否对本网站进行了授权,如果授权,将TouchID保存到本地,直接使用指纹登录,调用指纹登录。提示用户是否通过指纹登录系统,具体代码如下:mounted(){consttouchId=localStorage.getItem("touchId");constcertificate=localStorage.getItem("certificate");//如果是touchId存在,调用Fingerprintloginif(touchId&&certificate){//提示用户是否需要touchId登录setTimeout(()=>{if(window.confirm("您已授权本站指纹登录,是否登录innow?")){this.touchIDLogin(certificate,touchId);}},1000);}}最终效果如下:项目地址本文代码完整地址请前往:登录。vue在线体验地址:chat-system项目GitHub地址:chat-system-github

最新推荐
猜你喜欢