扫码登录认证技术原理介绍及实践

科技资讯 投稿 8900 0 评论

扫码登录认证技术原理介绍及实践

一、背景

主要目的是:

2、账号登录使用更加安全性;

 

二、处理流程

1、业务流程图

因为扫码的时候有两种处理逻辑,所以流程图有业务处理方案。

2、技术实现设计流图程

3、处理步骤说明

a、用户打开PC登录页面,PC登录页面向认证中心发起请求,认证中心生成uuid等信息,返回uuid等信息给前端,前端展示一个包含uuid的二维码。

b、PC端登录页面定时向认证中心轮询二维码的状态。

c、用户登录移动端,打开移动端摄像头扫描PC端登录页面的二维码。

d、移动端将二维码中包含的uuid等信息发送给认证中心,认证中心将二维码状态设置为“扫描成功”。

e、PC端登录页面轮询到二维码状态为“扫描成功”,提示“扫描成功”,以下图片仅供参考。

 

 

f、移动端展示弹出框,显示“登录”、“取消登录”按钮,同时将移动端当前登录的用户的可用账号列表展示出来供选择(单选),以下图片仅供参考。      

g、移动端将用户所选账号、当前移动端登录的token和二维码uuid等信息发送给认证中心。

h、认证中心将用户所选要登录的账号保存在二维码信息里面,并将二维码状态设置为“已授权”。

i、登录页面从轮询二维码不存在时,提示“二维码已过期”,以下图片仅供参考。

j、登录页面从轮询二维码状态为“已取销”时,提示“你已取消此次操作,你可再次扫描,或关闭窗口”。

k、登录页面从轮询二维码状态为“已授权”时,认证中心生成PC端登录的token,设置cookie,并向PC端前端发起重定向跳转。

程序处理时序图

三、代码实现

public class Auth2Login {
    public static void main(String[] args {
        //Step 1: 获取授权请求URL
        String authRequestUrl = "https://example.com/oauth/authorize";

        //Step 2: 向授权服务器发送请求,获取授权码
        String authCode = getAuthCode(authRequestUrl;

        //Step 3: 使用授权码,向认证服务器发送请求,获取access token
        String accessToken = getAccessToken(authCode;

        //Step 4: 使用access token,访问资源服务器,进行用户登录
        String userInfo = getUserInfo(accessToken;

        //Step 5: 根据user info进行用户登录
        login(userInfo;
    }

    public static String getAuthCode(String authRequestUrl {
        //TODO
        return null;
    }

    public static String getAccessToken(String authCode {
        //TODO
        return null;
    }

    public static String getUserInfo(String accessToken {
        //TODO
        return null;
    }

    public static void login(String userInfo {
        //TODO
    }
}

 

扫码登录认证关键代码片段

 /**
     * 初始化,主要通过请求基本参娄生成UUID,并把uuid写入redis
     * @param cmd 请求参数
     * @return
     */
    public Response init(LoginQrCodeInitCmd cmd {

        String clientId = cmd.getClientId(;
        String clientRedirectUri = cmd.getClientRedirectUri(;
        String appCode = cmd.getAppCode(;
        String subAppCode = cmd.getSubAppCode(;

        ClientDetailsE clientDetails = oauthService.loadClientDetails(clientId;
        if (clientDetails == null || clientDetails.getId( == null {
            return Response.buildFailure(AuthcenterCode.INVALID_CLIENT, String.format(AuthcenterCode.INVALID_CLIENT.getDesc(, clientId;
        }

        if (!clientDetails.getGrantTypes(.contains(GrantType.QR_CODE.toString( {
            return Response.buildFailure(AuthcenterCode.INVALID_GRANT_TYPE, String.format(AuthcenterCode.INVALID_GRANT_TYPE.getDesc(, clientId;
        }

        LoginQrCodeE qrCodeE = LoginQrCodeE.instance(.init(clientId, clientRedirectUri, appCode, subAppCode;
        return DataResponse.of(BeanToolkit.instance(.copy(qrCodeE, LoginQrCodeCO.class;
    }

    /**
     * 通过UUID获取登录二维码
     * @param uuid 唯一字符串
     * @return QR code对象
     */
    public LoginQrCodeE getLoginQrCode(String uuid {
        return LoginQrCodeE.instance(.of(uuid;
    }

    /**
     * 通过UUID扫码
     * @param uuid 唯一字符串
     * @return
     */
    public Response scan(String uuid {
        LoginQrCodeE.instance(.scan(uuid;
        return Response.buildSuccess(;
    }

    /**
     * 取消登录确认
     * @param uuid 唯一字符串
     * @return
     */
    public Response cancel(String uuid {
        LoginQrCodeE.instance(.cancel(uuid;
        return Response.buildSuccess(;
    }

    /***
     * 验证登录
     * @param cmd 用户登录对象信息
     * @return 如果成功返回登录信息结构体
     */
    public Response authorize(LoginQrCodeAuthorizeCmd cmd {

        String uuid = cmd.getUuid(;
        String selectedAccountId = cmd.getSelectedAccountId(;
        String token = cmd.getToken(;

        //是否有扫码
        if (LoginQrCodeE.instance(.of(uuid.notScanned( {
            return Response.buildFailure(AuthcenterCode.QR_CODE_NOT_SCANNED;
        }

        /**
         * 找出token
         */
        AccessTokenE accessTokenE = oauthRepository.findAccessToken(token;
        if (accessTokenE == null {
            return Response.buildFailure(AuthcenterCode.INVALID_TOKEN;
        }

        AccountE userAccount = oauthRepository.findAccountByToken(token;
        if (userAccount == null {
            // 当前令牌不存在用户态(账号)
            return Response.buildFailure(AuthcenterCode.TOKEN_ACCOUNT_RELA_NOT_EXIST;
        }
        List<String> userAccountIds = accountRepository.forceGetAccountIdsByMainUserId(userAccount.getMainUserId(;
        if (userAccountIds == null {
            // 当前账号异常
            return Response.buildFailure(AuthcenterCode.UNKNOWN_ACCOUNT;
        }

        if (!userAccountIds.contains(selectedAccountId {
            // 所选账号与当前令牌登录人信息不一致
            return Response.buildFailure(AuthcenterCode.INVALID_SWITCH_ACCOUNT;
        }

        LoginQrCodeE.instance(.authorize(uuid, selectedAccountId;
        return Response.buildSuccess(;
    }

    /**
     * 对外提供轮旬时间服务方法,当查询redis key=uuid是否超时
     * @param uuid 用户访问请求的UUID
     * @return 登录码状态对象
     * @throws OAuthSystemException
     */
    public LoginQrCodeE handle(String uuid throws OAuthSystemException {

        LoginQrCodeE loginQrCode = getLoginQrCode(uuid;

        // 当处于“已授权”状态时,才能触发准备登录
        if (loginQrCode.authorized( {
            return loginQrCode.ready(;
        }

        // 当处于“准备登录”状态时,才能触发登录
        if (loginQrCode.loginReady( {
            return login(loginQrCode;
        }

        return loginQrCode;
    }

    /**
     * 扫码登录
     * @param loginQrCode
     * @return
     * @throws OAuthSystemException
     */
    public LoginQrCodeE login(LoginQrCodeE loginQrCode throws OAuthSystemException {

        String clientId = loginQrCode.getClientId(;
        String accountId = loginQrCode.getAccountId(;

        ClientDetailsE clientDetails = clientDetailsRepository.findByClientId(clientId;

        AccountE userAccount = accountRepository.getAccountById(accountId;
        accountRepository.checkAccount(userAccount;

        String mainUserId = userAccount.getMainUserId(;
        MainUserE mainUser = mainUserRepository.getMainUserById(mainUserId;
        mainUserRepository.checkMainUser(mainUser;

        AuthorizeE authorize = oauthRepository.findAccountAuthorizeByAccountId(accountId;
        authorizeRepository.checkAuthorizeDataIntegrity(authorize;
        if (authorize == null {
            LOG.warn("Cannot find AuthorizeE[mainUserId={}]!", mainUserId;
            throw new UnknownAuthorizeException(;
        }

        AccessTokenE accessToken = oauthService.retrieveQrCodeAccessToken(clientDetails, authorize, userAccount, new HashSet<>(,
                new BizCodeE(loginQrCode.getAppCode(, loginQrCode.getSubAppCode(;

        return loginQrCode.login(accessToken.getToken(, accessToken.getRefreshToken(, accessToken.getCastgt(;
    }

 

 

 

编程笔记 » 扫码登录认证技术原理介绍及实践

赞同 (33) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽