谷歌授权登录开发

本文章主要为了实现google关联用户的服务
如果仅仅需要使用google邮箱登录,建议由前端实现google登录

google相关文档:https://developers.google.com/identity/protocols/oauth2

可以自己去谷歌开发者平台注册账号,获取到clientIdclientSecret

接下来 我的做法是前端以下方法点击登录后端会重定向到谷歌的授权页面,等待用户授权登录

@Value("${google.clientId}")
    private String clientId;
    @Value("${google.clientSecret}")
    private String clientSecret;
    @Value("${google.redirectUri}")
    private String redirectUri;
    @Value("${google.userInfoUri}")
    private String userInfoUri;
    // 令牌有效期(默认30分钟)
    @Value("${token.expireTime}")
    private int expireTime;

    @Autowired
    private QUserService quserService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private QVerificationTokenService qVerificationTokenService;

    @GetMapping("/login")
    public void getCode(String code, HttpServletRequest req, HttpServletResponse resp) throws GeneralSecurityException, IOException, ParseException {
    
    
        System.out.println(code);
        String refererUrl = req.getHeader("Referer") == null ? "https://qollect.cn" : req.getHeader("Referer");
        log.info("google 认证登录开始 ######### code={},refererUrl={}",code,refererUrl);

        String refererKey = SnowFlakeUtil.nextId().toString();
        redisCache.setCacheObject(refererKey, refererUrl);
        QUser userInfo = new QUser();
        QVerificationToken qVerificationToken = new QVerificationToken();
        HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
        GoogleClientSecrets clientSecrets = new GoogleClientSecrets();
        GoogleClientSecrets.Details details = new GoogleClientSecrets.Details();
        details.setClientId(clientId);
        details.setClientSecret(clientSecret);
        clientSecrets.setInstalled(details);
        GoogleIdToken googleIdToken;
        List<String> scopes = Arrays.asList("https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "openid");
        //获取token
        if (StringUtils.isEmpty(code)) {
    
    
            // 创建验证流程对象
            GoogleAuthorizationCodeFlow googleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow
                    .Builder(httpTransport, jsonFactory, clientSecrets, scopes)
                    // AccessType为离线offline,才能获得Refresh Token
                    .setAccessType("offline").build();
            // 返回跳转登录请求
            String uri = googleAuthorizationCodeFlow.newAuthorizationUrl().setState(refererKey).setRedirectUri(redirectUri).build();
            userInfo.setUrl(uri);
            resp.sendRedirect(uri);
            log.info("google 认证登录重定向 ######### code={},refererUrl={},uri={}",code,refererUrl,uri);
        }
    }

接着用户点完授权后 谷歌会回调你传的回调地址并带code,拿到code后获取用户信息

@Value("${google.clientId}")
    private String clientId;
    @Value("${google.clientSecret}")
    private String clientSecret;
    // 令牌秘钥
    @Value("${token.secret}")
    private String secret;
    @Value("${token.expireTime}")
    private int expireTime;
    @Autowired
    private CookieUtils cookieUtils;

    @GetMapping("/code")
    public void getCode(HttpServletRequest req, HttpServletResponse resp) throws IOException, GeneralSecurityException, ParseException {
    
    
// 获取用户信息
        String code = req.getParameter("code");
        String refererKey = req.getParameter("state");
        String refererUrl = redisCache.getCacheObject(refererKey);
        log.info("已认证回调 ######### code={},refererKey={},refererUrl={}", code, refererKey, refererUrl);

        HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
        GoogleClientSecrets clientSecrets = new GoogleClientSecrets();
        GoogleClientSecrets.Details details = new GoogleClientSecrets.Details();
        details.setClientId(clientId);
        details.setClientSecret(clientSecret);
        clientSecrets.setInstalled(details);
        List<String> scopes = Arrays.asList("https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "openid");
        GoogleAuthorizationCodeFlow googleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, clientSecrets, scopes)
                // AccessType为离线offline,才能获得Refresh Token
                .setAccessType("offline").build();
        GoogleAuthorizationCodeTokenRequest tokenRequest = googleAuthorizationCodeFlow.newTokenRequest(code);
        tokenRequest.setRedirectUri(redirectUri);
        tokenRequest.setGrantType("authorization_code");
        // 发起授权请求,获得Token和Refresh Token
        GoogleTokenResponse tokenResponse = tokenRequest.execute();
        String token = tokenResponse.getAccessToken();
        String refreshToken = tokenResponse.getRefreshToken();
        GoogleIdToken googleIdToken;
        String userToken = null;
        if (StringUtils.isNotBlank(tokenResponse.getIdToken())) {
    
    
            GoogleIdTokenVerifier idTokenVerifier = new GoogleIdTokenVerifier.Builder(googleAuthorizationCodeFlow.getTransport(), googleAuthorizationCodeFlow.getJsonFactory()).build();
            idTokenVerifier.verify(tokenResponse.getIdToken());
            googleIdToken = idTokenVerifier.verify(tokenResponse.getIdToken());
            if (googleIdToken != null && googleIdToken.getPayload() != null) {
    
    
                QUser userInfo = quserService.getOne(new LambdaQueryWrapper<QUser>().eq(QUser::getEmail, googleIdToken.getPayload().getEmail()));
                if (userInfo == null) {
    
    
                    userInfo = new QUser();
                }
                // 用户信息表
                userInfo.setToken(token);
                userInfo.setRefreshToken(refreshToken);
                userInfo.setEmail(googleIdToken.getPayload().getEmail());
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String sd = simpleDateFormat.format(new Date());
                userInfo.setCreateDate(simpleDateFormat.parse(sd));
                userInfo.setUpdateDate(simpleDateFormat.parse(sd));
                userInfo.setSources(SourcesConstants.SOURCES_GOOGLE);
                // json
                JSONObject json = new JSONObject(googleIdToken.getPayload());
                userInfo.setUsername(json.getString("name") + "");
                userInfo.setImage(json.getString("picture") + "");

                if (userInfo.getId() == null) {
    
    
                    userInfo.setId(SnowFlakeUtil.nextId());
                    quserService.insertInfo(userInfo);
                } else {
    
    
                    quserService.updateById(userInfo);
                }

                // 认证表
                QVerificationToken qVerificationToken = new QVerificationToken();
                qVerificationToken.setToken(token);
                qVerificationToken.setIdentifier(googleIdToken.getPayload().getEmail());
                qVerificationToken.setExpiresDate(simpleDateFormat.parse(sd));
                qVerificationTokenService.insertInfo(qVerificationToken);

                Map<String, Object> claims = new HashMap<>();
                claims.put(Constants.LOGIN_USER_KEY, token);
                long nowTime = System.currentTimeMillis();
                long expTime = 15 * 24 * 3600 * 1000;
                String uToken = Jwts.builder().setClaims(claims).setExpiration(new Date(nowTime + expTime)).signWith(SignatureAlgorithm.HS512, secret).compact();
                // 保存redis 缓存
                redisCache.setCacheObject(uToken, userInfo.getId(), expireTime, TimeUnit.MINUTES);
                // 保存 token 到 cookie
                cookieUtils.addTokenCookie(resp, uToken);

                log.info("已认证回调重定向跳转后写出数据到页面 ######### code={},refererKey={},refererUrl={},userToken={}", code, refererKey, refererUrl, uToken);

                resp.sendRedirect(refererUrl);
            }
        }

    }

猜你喜欢

转载自blog.csdn.net/leaning_java/article/details/129537084