VUEがQQの共同ログインを実現

注:このブログではXiaobaiの執筆に関するアイデアを紹介しています。以下のコンテンツとサードパーティのジャンプ環境は主にYu Shengjunから提供されています。

1. アイデア

1。ログインページで、使用可能な共同ログインインターフェース(サードパーティのログインアバター、 requestAddressを含むをバックグラウンドで照会します。

2.アバターをクリックしてQRコードスキャンインターフェイスに入ります

3. QQコードをスキャンした後、requestAddressのコールバックアドレスに従って、バックグラウンドのカスタムログインコールバックメソッドunionLoginCallbackを入力します

4.コールバックメソッドでユーザーのopenIdを取得し、アセンブリ後に定義されたフロントエンドアソシエーションページに戻ります(openIdに従ってユーザーが関連付けられているかどうかを照会し、アソシエーションが渡された場合、ユーザー情報は関連付けられたアカウントページに転送され、ユーザーはクリックすると直接ホームページにジャンプします。接続されていません)

5. [既存のアカウントに関連付ける]をクリックして、関連付けられているアカウントページに移動し、ユーザーのopenIdをページに渡します。

6.ユーザーは、関連付けられたアカウントページでプラットフォームのログインアカウントパスワードを入力し、ユーザーのopenIdをバックグラウンドに一緒に渡します。呼び出しメソッドは、プラットフォームのログインインターフェイスです。入力したアカウントパスワードが正しければ、ユーザーのopenIdが追加されますユーザーに対応するデータベースデータに移動し、ホームページにジャンプします。

第二に、開発コード

(1)データベースデータ

/ * 
 Navicat Premium Data Transfer 

 ソースサーバー:localhost 
 ソースサーバータイプ:MySQL 
 ソースサーバーバージョン:50647 
 ソースホスト:localhost:3306 
 ソーススキーマ:cyb 

 ターゲットサーバータイプ:MySQL 
 ターゲットサーバーバージョン:50647 
 ファイルエンコーディング:65001 

 日付:12/04 / 2020 02:42:17 
* / 

セット名utf8mb4; 
SET FOREIGN_KEY_CHECKS = 0; 

------------------------------ 
meite_userのテーブル構造
------------- ---------------- 
DROP TABLE IF EXISTS `meite_user`; 
CREATE TABLE `meite_user`( 
  ` USER_ID` int(12)NOT NULL AUTO_INCREMENT COMMENT 'user_id'、
  `MOBILE` varchar(11)CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'Mobile Number'、
  ` PASSWORD` varchar(64)CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'Password'、
  `USER_NAME` varchar(50)CHARACTER utf8_general_ci NULL DEFAULT NULL COMMENT 'user name'、
  `SEX` tinyint(1)NULL DEFAULT 0 COMMENT 'sex 1 male 2 female'、
  ` AGE` tinyint(3)NULL DEFAULT 0 COMMENT 'age'、
  `CREATE_TIME` timestamp(0 )NULL DEFAULT NULL COMMENT '登録時間'、
  `IS_AVALIBLE` tinyint(1)NULL DEFAULT 1 COMMENT 'Available 1 normal 2 frozen'、
  ` PIC_IMG` varchar(255)CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'ユーザーアバター' 、
  `QQ_OPENID` varchar(50)CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'QQ共同ログインID'、
  `WX_OPENID` varchar(50)CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '微信公众号关注id'、
  PRIMARY KEY( `USER_ID`)USING BTREE、
  UNIQUE INDEX` MOBILE_UNIQUE`( `MOBILE`)USING BTREE 
)ENGINE = InnoDB AUTO_INCREMENT = 87 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户会员表' ROW_FORMAT 

------------------------------ 
meite_userのレコード
-------------- --------------- 
INSERT INTO `meite_user` VALUES(86、 '18774833827'、 'E10ADC3949BA59ABBE56E057F20F883E'、 '1'、1、0、 '2020-03-15 22:34: 45 '、0、' 1 '、' 3EAB229E0EAAB047174224A5845B224E '、' oOX38w3WD3JUjL5ORcr4OADNqfSw '); 

SET FOREIGN_KEY_CHECKS = 1;

(2)共同ログインインターフェース

import com.cyb.base.BaseResponse; 
import com.cyb.member.api.dto.resp.UnionLoginDto; 
import io.swagger.annotations.Api; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.RequestParam; 
import org.springframework.web.bind.annotation.ResponseBody; 

import java.util.List; 

@Api(tags = "联合登陆
インタフェース")パブリックインターフェースMemberUnionLoginService { 


    / ** 
     *に基づいて異なる別の联合登陆ID 
     * 
     * @param unionPublicId 
     * @return 
     * / 
    @GetMapping( "/ unionLogin")
    BaseResponse <String> unionLogin(@ RequestParam( "unionPublicId")String unionPublicId); 

    / **
     *共同ログインコールバックインターフェース
     * 
     * @return 
     * / 
    @GetMapping( "/ login / oauth / callback")
    String unionLoginCallback(@RequestParam( "unionPublicId")String unionPublicId); 

    / ** 
     *查询当前开通的溝道
     * 
     * @return 
     * / 
    @GetMapping( "/ unionLoginList")
    @ 
    ResponseBody BaseResponse <List <UnionLoginDto >> unionLoginList(); 
}

(3)共同ログイン実装クラス

import com.alibaba.fastjson.JSONObject; 
import com.cyb.base.BaseApiService; 
import com.cyb.base.BaseResponse; 
import com.cyb.bean.CybBeanUtils; 
import com.cyb.member.api.dto.resp.UnionLoginDto; 
import com.cyb.member.api.service.MemberUnionLoginService; 
import com.cyb.member.impl.entitydo.UnionLoginDo; 
import com.cyb.member.impl.mapper.UnionLoginMapper; 
import com.cyb.member.impl.strategy.UnionLoginStrategy; 
import com.cyb.utils.SpringContextUtils; 
import com.cyb.utils.TokenUtils; 
import org.apache.commons.lang3.StringUtils; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin; 
import org.springframework.web.bind.annotation.RestController; 
import org.springframework.web.context.request.RequestContextHolder; 
import org.springframework.web.context.request.ServletRequestAttributes; 

import javax.servlet.http.HttpServletRequest; 
import java.util.List; 


// @ RestController 
@Controller 
@CrossOrigin 
public class MemberUnionLoginServiceImpl extends BaseApiService implements MemberUnionLoginService { 

    @Autowired 
    private UnionLoginMapper unionLoginMapper; 
    @Autowired  
    プライベートTokenUtils tokenUtils;
    @Value( "$ {cyb.login.vue.bindingurl}")
    プライベート文字列bindingurl; 

    @オーバーライド
    public BaseResponse <String> unionLogin(String unionPublicId){ 
        if(StringUtils.isEmpty(unionPublicId)){ 
            return setResultError( "unionPublicId cannot be empty"); 
        } 
        //チャネルIDに基づいてユニオンの基本情報をクエリします
        UnionLoginDo unionLoginDo = unionLoginMapper.selectByUnionLoginId( ); 
        if(unionLoginDo == null){ 
            return setResultError( "チャネルが閉じているか、存在しない可能性があります"); 
        } 
        String state = tokenUtils.createToken( "member.unionLogin"、 ""); 
    @Override 
        文字列requestAddres = unionLoginDo.getRequestAddress()+ "&state =" + state;
        JSONObject dataObjects = new JSONObject(); 
        dataObjects.put( "requestAddres"、requestAddres); 
        return setResultSuccess(dataObjects); 

    } 

    public String unionLoginCallback(String unionPublicId){ 
        //チャネルIDに基づいて基本的なユニオン情報をクエリする
        UnionLoginDo unionLoginDo = unionLoginMapper.selectByUnionLoginId( unionPublicId); 
        String unionBeanId = unionLoginDo.getUnionBeanId(); 
        //ビーニーに基づいてSpringコンテナからストラテジークラスを検索します
        UnionLoginStrategy unionLoginStrategy = SpringContextUtils.getBean(unionBeanId、UnionLoginStrategy.class); 
        //現在のスレッドに従ってリクエストオブジェクト
        HttpServletRequestリクエストを取得します=((ServletRequestAttributes)
                (RequestContextHolder.currentRequestAttributes()))。getRequest(); 
        String openId = unionLoginStrategy.unionLoginCallback(request、unionLoginDo); 
        JSONObject jsonObject = new JSONObject(); 
        jsonObject.put( "openId"、openId); 
        jsonObject.put( "unionPublicId"、unionPublicId); 
        String openToken = 
        List <UnionLoginDo> unionLoginList = unionLoginMapper.selectByUnionLoginList();
                tokenUtils.createToken( "mayikt.unionLogin。"、jsonObject.toJSONString()); 
        "redirect:" + bindingurl + openTokenを返します。
    } 

    @Override 
    public BaseResponse <List <UnionLoginDto >> unionLoginList(){ 
        if(unionLoginList == null){ 
            return setResultError( "当前没有可用導管道"); 
        } 
        List <UnionLoginDto> unionLoginDtos = CybBeanUtils.doToDtoList(unionLoginList、UnionLoginDto.class); 
        setResultSuccess(unionLoginDtos);を返します。
    } 
}

 

(4)共同ログイン戦略モードのインターフェース

    / * 
    *共同ログインコールバック
    * @Author陈远波
    * @Date 2020-04-12 
     * @param null 
    * @return 
    * / 
    String unionLoginCallback(HttpServletRequest request、UnionLoginDo unionLoginDo); 

    / * 
    *ユーザーのopenIDに基づいてチャネル情報を取得
    * @Author陈远波
    * @Date 2020-04-12 
     * @param openId user openID 
    * @return 
    * / 
    UserDo getDbOpenId(String openId); 

    / * 
    *ユーザーIDに応じてユーザーのopenIDを変更する
    * @Author陈远波
    * @Date 2020-04-12 
     * @ param userId user id 
     * @param openId user openId  
    * @return 
    * /
    int updateUseOpenId(Long userId、String openId); 
}

(E)QQ 共同ログイン戦略モデル実装クラス

@Component 
パブリッククラスQQUnionLoginStrategyは、UnionLoginStrategy { 
    @Value( "$ {cyb.login.qq.accesstoken}")
    private String qqAccessTokenAddres;を実装します。
    @Value( "$ {cyb.login.qq.openid}")
    プライベート文字列qqOpenIdAddres; 
    @Autowired 
    プライベートUserMapper userMapper; 
    @Override 
    public String unionLoginCallback(HttpServletRequest request、UnionLoginDo unionLoginDo){ 
        String code = request.getParameter( "code"); 
        if(StringUtils.isEmpty(code)){ 
            nullを返す; 
        } 
        // 
        1。根拠授权码获取accessToken // 1.根拠授权码获取accessToken
        文字列newQQAccessTokenAddres = qqAccessTokenAddres.replace( "{client_id}"
        }
                、unionLoginDo.getAppId())。replace( "{client_secret}"、unionLoginDo.getAppKey())。
                replace( "{code}"、code).replace( "{redirect_uri}"、unionLoginDo.getRedirectUri()); 
        文字列resultAccessToken = HttpClientUtils.httpGetResultString(newQQAccessTokenAddres); 
        boolean contains = resultAccessToken.contains( "access_token ="); 
        if(!contains){ 
            return null; 
        } 
        String [] split = resultAccessToken.split( "="); 
        文字列accessToken = split [1]; 
        if(StringUtils.isEmpty(accessToken)){ 
            nullを返す; 
        // 2. accessToken获取用户的openidに基づく 
        文字列resultQQOpenId = HttpClientUtils.httpGetResultString(qqOpenIdAddres + accessToken); 
        if(StringUtils.isEmpty(resultQQOpenId)){ 
            nullを返します。
        } 
        boolean openid = resultQQOpenId.contains( "openid"); 
        if(!openid){ 
            nullを返す; 
        } 

        文字列配列[] = resultQQOpenId.replace( "callback({"、 "").replace( "});"、
                "").replace( "\" "、" ").trim()。split(" : "); 
        String openId = array [2]; 

        return openId;

       return userMapper.selectByQQOpenId(openId); 
    }

    @Override 
    public int updateUseOpenId(Long userId、String openId){ 
        return userMapper.updateUserOpenId(userId、openId); 
    } 
}

 

(6)ログインインターフェース

@RestController 
@Api(tags = "Member Login Service")
パブリックインターフェイスMemberLoginService { 
    / * 
    * 
    * @Author陈远波
    * @Date 2020-03-25 
     * @param @RequestHeader( "X-Real-IP")nginxからのリクエストヘッダーブラウザの実際のIPを
     取得します* * RequestHeader( "channel")リクエストヘッダーからログインソースPCを取得します、Android、iOS 
    * @return 
    * / 
    @PostMapping( "/ login")
    @ApiOperation(value = "Member Login"、notes = "シリアル化のパラメーターを受信する")
    BaseResponse <JSONObject> login(@RequestBody UserLoginDto userLoginDto、@RequestHeader( "X-Real-IP")
            String sourceIp、@RequestHeader( "channel")String channel、@RequestHeader( "deviceInfor" )String deviceInfor); 
}

ゴードン記録インターフェース

 

@RestController 
@ Slf4j 
@CrossOrigin 
public Class MemberLoginServiceImpl extends BaseApiService implements MemberLoginService { 
    @Autowired 
    private UserMapper userMapper; 
    @Autowired 
    プライベートTokenUtils tokenUtils; 
    @Value( "$ {cyb.login.token.prefix}")
    private String loginTokenPrefix; 
    @Autowired 
    プライベートAsyncLoginLogManage asyncLoginLogManage; 
    @Autowired 
    プライベートUserLoginLogMapper userLoginLogMapper; 
    @Autowired 
    プライベートChannelUtils channelUtils; 

    @Override  
    public BaseResponse <JSONObject> login(UserLoginDto userLoginDto、String sourceIp
            、文字列チャネル、文字列deviceInfor){ 
        //パラメータ验证 
        String mobile = userLoginDto.getMobile(); 
        if(StringUtils.isEmpty(mobile)){ 
            return setResultError( "mobile parameter cannot be empty"); 
        } 
        String passWord = userLoginDto.getPassWord (); 
        if(StringUtils.isEmpty(userLoginDto.getPassWord())){ 
            return setResultError( "passWord parameter cannot be empty"); 
        } 
        if(!channelUtils.existChannel(channel)){ 
            return setResultError( "Login type error! "); 
        } 
        //データベースにクエリを実行します
        String newPassWord = MD5Util.MD5(passWord); 
        UserDo loginUserDo = userMapper.login(mobile、newPassWord);
        if(loginUserDo == null){ 
        log.info(Thread.currentThread().GetName()+ "Processing Process 1"); 
            return setResultError( "携帯電話番号またはパスワードが正しくありません!");
        } 
        //デバイス情報
        if(StringUtils.isEmpty(deviceInfor)){ 
            return setResultError( "设备信息不可能にする空!"); 
        } 

        // 
        获取userId Long userId = loginUserDo.getUserId(); 
        String userToken = tokenUtils.createToken(loginTokenPrefix、userId + ""); 

        JSONObject resultJSON = new JSONObject(); 
        resultJSON.put( "userToken"、userToken); 
        文字列wxOpenId = loginUserDo.getWxOpenId(); 
        String openIdToken = userLoginDto.getOpenIdToken(); 
        //写入日志
        asyncLoginLogManage.loginLog(openIdToken、wxOpenId、mobile、userId、sourceIp、new Date()、userToken 
                、channel、deviceInfor); 
        log.info(Thread.currentThread()。getName()+ "处理流程3"); 
        setResultSuccess(resultJSON);を返します。
    } 
    public void loginLog(Long userId、String loginIp、Date loginTime、String loginToken、String channel、
                         String equipment){ 
        UserLoginLogDo userLoginLogDo = new UserLoginLogDo(userId、loginIp、loginTime、loginToken、channel、equipment); 
        log.info(Thread.currentThread()。getName()+ "、userLoginLogDo:" + userLoginLogDo.toString()+ "、流程2"); 
        userLoginLogMapper.insertUserLoginLog(userLoginLogDo);
        log.info(Thread.currentThread()。getName()+ "处理流程2"); 
    } 
}

(7)設定ファイル

cyb:
   login:
      token:
        prefix:memberlogin 
        channel:pc、android、ios 
      qq:
        accesstoken:https : //graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id={client_id}&client_secret={client_secret}&code= {code}&redirect_uri = {redirect_uri} 
        openid:https 
      : 
        //graph.qq.com/oauth2.0/me?access_token = wx:accesstoken:https : //api.weixin.qq.com/sns/oauth2/access_token? appid = APPID&secret = SECRET&code = CODE&grant_type = authorization_code 
      vue:
        bindingurl:http : //127.0.0.1:8849 /mayikt_mt_shop/relation_login.html?openIdToken=

 

3. 注意が必要な事項: 

このプロセスでは、クロスドメインエラーが発生します

多くの解決策がありますが、ここではコメントの形式を使用して解決します。具体的な解決策は次のとおりです。

1. 応答ヘッダーに設定して、小規模企業にのみ適したクロスドメインを許可する

响应配置 response.setHeader( "Access-Control-Allow-Origin"、 "*");

2. HttpClient を使用した低い転送効率

3. 使用JSONP 処理、JSON P- 最大の欠点支援のGET 要求はサポートされていないポストの要求を

4. nginxを使用して、ブラウザーによってアクセスされるプロジェクトのドメイン名またはポート番号とインターフェースプロジェクトが一致するように構成します。

    www.mayikt.com/vue forward to vue プロジェクト

        www.mayikt.com/api がインターフェースプロジェクトに転送されました

5. nginxで直接クロスドメインを許可するコードを設定できます

    "Access-Control-Allow-Origin"、 "*"

6. ゲートウェイは、クロスドメイン許可するためnginxと同様のコードで構成することもできます

    "Access-Control-Allow-Origin"、 "*"

7. SpringBoot アノテーションを使用して、クロスドメインの問題@CrossOrigin を解決する

8. マイクロサービスゲートウェイを使用して、ブラウザーがアクセスするアイテムとインターフェースアイテムのドメイン名またはポート番号の整合性を設定することもできます。

第四に、エフェクト表示

 1.ホームページにログインします

2.サードパーティのログインをクリックして、バーコードスキャンインターフェイスにジャンプします。

コードスキャン時の携帯電話インターフェース

 

確認関連付けインターフェイスに入る

関連付けるログインアカウントのパスワードを入力してください

上記の内容について質問がある場合は、メッセージに注意を払うことができます。ソースを指定してください

 

 

 

 

 

 

 

おすすめ

転載: www.cnblogs.com/chenyuanbo/p/12683531.html