android - 使用 YouTube v3 api 身份验证时 OAuth2.0 无效凭据
问题描述
我花了几天时间研究如何通过 Google api 控制台和 Firebase api 实现“简单”的 Google 登录。由于我没有服务器,我希望只有在用户使用该应用程序时才能访问他的帐户。我的目标是能够获取用户的频道 ID,这样我就可以加载他所有上传的视频。
为此,我在 google 控制台 api 中创建了一个新项目,将其链接到 Firebase 并使用此教程链接将其集成到我的应用程序中。我到了用户可以选择Gmail帐户并登录的地步,该应用程序还提示用户需要允许的一系列YouTube权限。之后,我得到了用户的 accountUid(与 Firebase 控制台中显示的相同)。
从这一点开始,我感到困惑,因为一些教程提到了我没有的令牌访问、刷新令牌、客户端 ID、客户端密码,并且不确定这些凭据是否对我的应用程序是必需的。
用户成功登录后,我使用此 API 调用来获取他的 YouTube 帐户的频道:
@GET("channels")
fun getChannelsList(@Query("part") part :String = "contentDetails,snippet",@Query("mine") mine : Boolean = true, @Header("Authorization") accessToken : String) : Single<ChannelResponse>
但我收到了这个错误:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "authError",
"message": "Invalid Credentials",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Invalid Credentials"
}
}
从这个链接中,我还尝试将“Bearer”作为标题值的一部分,结果相同。
我也试过 googleSignInAccount.idToken 但它也没有帮助。
这是我的 LoginActivity 的代码:
class LoginActivity : BaseActivity(), View.OnClickListener,OnCompleteListener<AuthResult>{
var idTokenString = ""
val TAG = "LoginActivity"
val mAuth = FirebaseAuth.getInstance()
private var mAuthListener: FirebaseAuth.AuthStateListener? = null
var googleAccount : GoogleSignInAccount?=null
override fun layoutRes(): Int {
return app.globe.com.youtubeplaylist.R.layout.activity_login
}
override fun initUI() {
login.setOnClickListener(this)
logout.setOnClickListener(this)
}
companion object {
const val RC_SIGN_IN = 1000
}
private var googleSignInClient : GoogleSignInClient?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(app.globe.com.youtubeplaylist.R.string.default_web_client_id))
.requestEmail()
.requestScopes(Scope("https://www.googleapis.com/auth/youtube.readonly"),
Scope("https://www.googleapis.com/auth/youtube.force-ssl"))
.build()
googleSignInClient = GoogleSignIn.getClient(this,gso)
googleSignInClient!!.signInIntent
}
override fun onStart() {
super.onStart()
val currentUser = mAuth.currentUser
checkAccount(currentUser)
}
override fun onClick(v: View) {
when (v.id) {
app.globe.com.youtubeplaylist.R.id.login -> {
signIn()
}
app.globe.com.youtubeplaylist.R.id.logout ->{
signOut()
}
}
}
private fun signOut()
{
FirebaseAuth.getInstance().signOut()
checkAccount(null)
}
private fun signIn() {
val signInIntent = googleSignInClient!!.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
// The Task returned from this call is always completed, no need to attach
// a listener.
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
// Google Sign In was successful, authenticate with Firebase
googleAccount = task.getResult(ApiException::class.java)
firebaseAuthWithGoogle(googleAccount!!)
} catch (e: ApiException) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e)
// ...
}
}
}
private fun firebaseAuthWithGoogle(acct : GoogleSignInAccount)
{
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.id)
val credential = GoogleAuthProvider.getCredential(acct.idToken, null)
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, this)
}
override fun onComplete(task: Task<AuthResult>) {
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success")
var user = mAuth.currentUser
checkAccount(user)
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.exception)
Snackbar.make(main_layout, "Authentication Failed.", Snackbar.LENGTH_SHORT).show()
checkAccount(null)
}
}
private fun checkAccount(account : FirebaseUser?)
{
if(account!=null)
{
val mainIntent = Intent(this,MainActivity::class.java)
startActivity(mainIntent)
}
else
{
login.visibility = View.VISIBLE
logout.visibility = View.GONE
}
}
}
谢谢!
解决方案
那default_web_client_id
可能是错的。
不管app.globe.com.youtubeplaylist.R.string.default_web_client_id
可能是什么。
请参阅GoogleSignInOptions.Builder。requestIdToken (String serverClientId)
:
指定请求已验证用户的 ID 令牌。
请求 ID 令牌需要指定服务器客户端 ID。
serverClientId
将验证令牌完整性的服务器的客户端 ID。
转到console.firebase.google.com,选择项目,然后单击
Authentication
> Sign-In method
> Google
> Web SDK configuration
。
在那里您可以找到要使用的“Web 客户端 ID”和“Web 客户端密码”。
同样在 Google Cloud API 凭据页面上,作为“Web 应用程序的客户端 ID”。
范围https://www.googleapis.com/auth/youtube.force-ssl
可能需要范围https://www.googleapis.com/auth/youtube
(这两者都用于管理 YouTube 帐户)。对于查看内容,范围https://www.googleapis.com/auth/youtube.readonly
就足够了。
推荐阅读
- python - Juypter 不会从 Anaconda 启动
- machine-learning - 多元回归模型的条件
- mysql - 键应该是索引还是复合主键
- java - Java中ArrayList的最大容量是多少?
- javascript - 使用 JavaScript 打开引导模式后,如何更改单击按钮的值?
- c# - Restsharp post 方法不起作用,Web api post 方法接收空值
- stata - 不满足条件时删除 ids 的整个时间序列
- powershell - 如何在 cmd/powershell 中创建具有增量文件名的批量空文件?
- android - PostDelayed 和 Handler 无法正常工作并立即运行
- python - 如何从python中原始列表大小的3/4的列表中创建一个新列表?