GVKun编程网logo

android – Oauth 2无法交换访问令牌的代码,返回“invalid_grant”(无法再进行口令登陆,尝试失败次数过多)

14

在本文中,您将会了解到关于android–Oauth2无法交换访问令牌的代码,返回“invalid_grant”的新资讯,同时我们还将为您解释无法再进行口令登陆,尝试失败次数过多的相关在本文中,我们将

在本文中,您将会了解到关于android – Oauth 2无法交换访问令牌的代码,返回“invalid_grant”的新资讯,同时我们还将为您解释无法再进行口令登陆,尝试失败次数过多的相关在本文中,我们将带你探索android – Oauth 2无法交换访问令牌的代码,返回“invalid_grant”的奥秘,分析无法再进行口令登陆,尝试失败次数过多的特点,并给出一些关于Android Auth错误:“GetToken失败,状态码为:INVALID_AUDIENCE”、Android oauth2 无法获得 AuthToken、Android R.java令牌“int”上的语法错误,此令牌后预期的VariableDeclaratorId、Android Retrofit2刷新Oauth 2令牌的实用技巧。

本文目录一览:

android – Oauth 2无法交换访问令牌的代码,返回“invalid_grant”(无法再进行口令登陆,尝试失败次数过多)

android – Oauth 2无法交换访问令牌的代码,返回“invalid_grant”(无法再进行口令登陆,尝试失败次数过多)

我发现当我的重定向uri为“urn:ietf:wg:oauth:2.0:oob”时,我可以通过OAuth 2.0进行身份验证,但是用户被迫复制代码,然后返回一个活动并将其粘贴到领域.我希望体验比这更优雅.当重定向uri是“http:// localhost”时,(即使返回了访问代码)我也无法将其替换为api的访问令牌.这是我的交换代码:

ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
                    0);
            nameValuePairs.add(new BasicNameValuePair("client_id",oauth2clientCredentialsMark1.CLIENT_ID));
            nameValuePairs.add(new BasicNameValuePair("client_secret",oauth2clientCredentialsMark1.CLIENT_SECRET));
            nameValuePairs.add(new BasicNameValuePair("code",accessCode));
            nameValuePairs.add(new BasicNameValuePair("grant_type","authorization_code"));
            nameValuePairs.add(new BasicNameValuePair("redirect_uri",oauth2clientCredentialsMark1.REDIRECT_URI));
                    //"http://localhost"

            String url = "https://accounts.google.com/o/oauth2/token";
            //url += URLEncodedUtils.format(nameValuePairs,"utf-8");

            Log.d("print",url);
            HttpPost hPost = new HttpPost(
                    url);
            hPost.setHeader("content-type","application/x-www-form-urlencoded");

            hPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

此代码始终返回{“error”:“invalid_grant”}给出了什么?

我的应用程序基于样本@ https://github.com/ddewaele/LatitudeOAuth2Sample,我一直在关注教程@ http://code.google.com/apis/accounts/docs/OAuth2InstalledApp.html

解决方法

看来您的代码是正确的.该错误来自 OAuth2 spec section-5.2.

The provided authorization grant (e.g. authorization code,resource owner credentials) or refresh token is invalid,expired,revoked,does not match the redirection URI used in the authorization request,or was issued to another client.

最有可能的是,您的应用程序尚未得到用户的授权.

回答你关注的问题:

the user is forced to copy the code,then go back one activity and paste it into a field

你能澄清一下oauth2 flow (scenario),你在开发什么?

Android Auth错误:“GetToken失败,状态码为:INVALID_AUDIENCE”

Android Auth错误:“GetToken失败,状态码为:INVALID_AUDIENCE”

已经有关于这个模糊的错误代码的几个问题,但是没有一个解决了这个问题,所以我再试一次.首先,这里是登录的样板代码.
GoogleSignInoptions gso = new GoogleSignInoptions.Builder(GoogleSignInoptions.DEFAULT_SIGN_IN)
        .requestemail()
        .requestServerAuthCode("web app client ID copied from Dev API Console",false)
        .build();


  mGoogleapiclient = new Googleapiclient.Builder(this).enableAutoManage(this,this).addApi(Auth
        .GOOGLE_SIGN_IN_API,gso).build();

  Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleapiclient);
  startActivityForResult(signInIntent,RC_SIGN_IN);

有了这个代码,我得到一个对话框,可以选择适当的用户帐号.好极了!但是,我在onActivityResult中获取一个取消的代码,所以我检查logcat并注意标题中的错误消息.然后,我在寻找有这个问题的其他人,但是还没有弄清楚我的情况是什么问题.

所以我们来看看其他帖子中的常见问题.

> Firebase控制台显示我的应用程序已注册正确的SHA-1和SHA-256指纹
>发布和调试版本都使用相同的密钥库
>在Google Api管理器中,配置了我的“OAuth同意屏幕”
>我还验证了授权的重定向URI的域
>我已经重新下载了Firebase的GoogleServices.json文件,只是为了确保
>没有包名称问题.事实上,Firebase Analytics在这个应用程序中一直运行得很好
>在Play Store开发者控制台中,我的OAuth客户端显示在“设置 – > API访问”
>我的Firebase项目在Play Store开发控制台“已连结帐户”设定部分中连结
>我已经等了10个小时,只是看看Google的后端是否需要时间来设置

对于可搜索性,在标题中的logcat错误消息之后,我得到以下logcat打印.

You have wrong OAuth2 related configurations,please check. Detailed
error: INVALID_AUDIENCE

解决方法

您的Web客户端ID必须与Firebase相同的用户帐户生成,而不是您的Play Store帐户.在我的情况下,这两个帐户是分开的,Google会抛出此错误,而不是正确链接信息.我的Firebase帐户与我的Play Store帐户相关联,但这显然不意味着将分享网络客户端ID.我尝试了一些其他解决方案,例如链接API管理器帐户,这也不起作用.您必须在Firebase在与您的Firebase帐户相同的API Manager帐户中使用的同一项目中创建Web客户端ID.

Android oauth2 无法获得 AuthToken

Android oauth2 无法获得 AuthToken

OSC 请你来轰趴啦!1028 苏州源创会,一起寻宝 AI 时代

最近在做一个需要用到 Gmail api 的 App,其中用到了 oauth2,在获得 AuthToken 的时候,得到的 AuthToken 总是个 null,也就是说获得不了 AuthToken。我看抛出了 IOException,初步猜测是不是因为功夫网拦截了 Google 的 API,所以 IOException,所以导致了获得不了 AuthToken? (因为得到的 AuthToken 是在一个回调里完成的,我加了断点也不停,所以也没法看出来具体是哪里出的问题,只能根据异常猜测一下),各位有没有开发过相关的项目的,遇到过这个问题吗,该如何解决呢,是否是功夫网的原因呢,要是的话我就放弃了,不折腾了。

下面是代码片段:

class AuthTokenTask extends AsyncTask<String, String, String> {

		String token = null;
		
		@Override
		protected String doInBackground(String... params) {
			
			AccountManager accountManager = AccountManager.get(getApplicationContext());
			Account me = accountManager.getAccountsByType("com.google")[0];
			
			accountManager.getAuthToken(me, "oauth2:https://mail.google.com/", null, true, new AccountManagerCallback<Bundle>() {

				@Override
				public void run(AccountManagerFuture<Bundle> future) {
					try {
						//15, TimeUnit.SECONDS
						token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
						Log.i(AuthTokenTask.class.getName(), token);
					} catch (OperationCanceledException e) {
						e.printStackTrace();
					} catch (AuthenticatorException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}, null);

			return token;
		}
		
		@Override
		protected void onPostExecute(String result) {
			mailProperties.oauthToken = result;
			super.onPostExecute(result);
		}
		
	}

LogCat 截图:




Android R.java令牌“int”上的语法错误,此令牌后预期的VariableDeclaratorId

Android R.java令牌“int”上的语法错误,此令牌后预期的VariableDeclaratorId

我在R.java文件中不断生成以下内容:

public static final class id {
    public static final int   =0x7f0500ae;

我做了研究,它都指向了字符串文件.我检查了我的字符串文件,没有错误.应用程序不会在其他任何地方产生错误,只是生成这一行.

有人可以请帮助.

解决方法:

我有同样的问题,发现奇怪的是我的strings.xml文件没有显示任何错误,但能够通过在strings.xml文件中搜索空字符串名称值来解决.

实测:

<string name="">Username</string>

变成:

<string name="lblUsername">Username</string>

工作,并能够编译,希望这有帮助.

Android Retrofit2刷新Oauth 2令牌

Android Retrofit2刷新Oauth 2令牌

我正在使用Retrofit和OkHttp库.
所以我有Authenticator哪个authantate用户如果得到401响应.

我的build.gradle是这样的:

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.okhttp3:okhttp:3.1.2'

而我的自定义验证器在这里:

import java.io.IOException;
import okhttp3.Authenticator;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;

public class CustomAuthanticator  implements Authenticator {
@Override
public Request authenticate(Route route,Response response) throws IOException {

    //refresh access token via refreshtoken

    Retrofit client = new Retrofit.Builder()
            .baseUrl(baseurl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    APIService service = client.create(APIService.class);
    Call<RefreshTokenResult> refreshTokenResult=service.refreshUserToken("application/json","application/json","refresh_token",client_id,client_secret,refresh_token);
    //this is syncronous retrofit request
    RefreshTokenResult refreshResult= refreshTokenResult.execute().body();
    //check if response equals 400,mean empty response
    if(refreshResult!=null) {
       //save new access and refresh token
        // than create a new request and modify it accordingly using the new token
        return response.request().newBuilder()
                .header("Authorization",newaccesstoken)
                .build();

    } else {
        //we got empty response and return null
        //if we dont return null this method is trying to make so many request
        //to get new access token
        return null;

    }

}}

这是我的APIService类:

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Query;


public interface APIService {


@FormUrlEncoded
@Headers("Cache-Control: no-cache")
@POST("token")
public Call<RefreshTokenResult> refreshUserToken(@Header("Accept") String accept,@Header("Content-Type") String contentType,@Field("grant_type") String grantType,@Field("client_id") String clientId,@Field("client_secret") String clientSecret,@Field("refresh_token") String refreshToken);
}

我正在使用这样的说明:

CustomAuthanticator customAuthanticator=new CustomAuthanticator();
OkHttpClient okClient = new OkHttpClient.Builder()
        .authenticator(customAuthanticator)
        .build();
Gson gson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
        .create();
Retrofit client = new Retrofit.Builder()
        .baseUrl(getResources().getString(R.string.base_api_url))
        .addConverterFactory(GsonConverterFactory.create(gson))
        .client(okClient)
        .build();

//then make retrofit request

所以我的问题是:有时我得到新的访问令牌并继续工作,提出新的请求.但是有时候我得到400响应,这意味着空的响应.所以我的旧刷新令牌无效,我不能得到新的令牌.通常我们的刷新令牌在1年后到期.那么我该怎么做呢请帮帮我 !

解决方法

@Edit 07.04.2017:

我更新了这个答案,因为它有点旧,我的情况改变了 – 我知道我有一个后台服务,

首先刷新令牌过程是关键过程.在我的应用程序和大多数应用程序中执行此操作:如果刷新令牌失败,注销当前用户并警告用户登录(也许您可以根据您重新启动刷新令牌进程2-3-4次)

@Important注意:请在Authenticator或Interceptor中刷新令牌时进行同步请求,因为您必须阻止该线程,直到您的请求完成,否则您的请求将使用旧的和新的令牌执行两次.

无论如何我会一步一步的解释一下:

步骤1:请参考singleton pattern,我们将创建一个类,负责返回我们的改装实例,无论何时我们想访问.由于它的静态,如果没有可用的实例,它只创建一个实例,当你调用它总是返回这个静态实例.这也是Singleton设计模式的基本定义.

public class RetrofitClient {

private static Retrofit retrofit = null;

private RetrofitClient() {
    // this default constructor is private and you can't call it like :
    // RetrofitClient client = new RetrofitClient();
    // only way calling it : Retrofit client = RetrofitClient.getInstance();
}

public static Retrofit getInstance() {
    if (retrofit == null) {
        // my token authenticator,I will add this class below to show the logic
        TokenAuthenticator tokenAuthenticator = new TokenAuthenticator();

        // I am also using interceptor which controls token if expired
        // lets look at this scenerio : if my token needs to refresh after 10 hours but I came
        // to application after 50 hours and tried to make request.
        // ofc my token is invalid and if I make request it will return 401
        // so this interceptor checks time and refresh token immediately before making request and after makes current request
        // with refreshed token. So I do not get 401 response. But if this fails and I get 401 then my TokenAuthenticator do his job.
        // if my TokenAuthenticator fails too,basically I just logout user and tell him to relogin.
        TokenInterceptor tokenInterceptor = new TokenInterceptor();


        // this is the critical point that helped me a lot.
        // we using only one retrofit instance in our application
        // and it uses this dispatcher which can only do 1 request at the same time

        // the docs says : Set the maximum number of requests to execute concurrently.
        // Above this requests queue in memory,waiting for the running calls to complete.

        dispatcher dispatcher = new dispatcher();
        dispatcher.setMaxRequests(1);

        // we using this OkHttp,you can add authenticator,interceptors,dispatchers,// logging stuff etc. easily for all your requests just editing this OkHttp
        OkHttpClient okClient = new OkHttpClient.Builder()
                .connectTimeout(Constants.CONNECT_TIMEOUT,TimeUnit.SECONDS)
                .readTimeout(Constants.READ_TIMEOUT,TimeUnit.SECONDS)
                .writeTimeout(Constants.WRITE_TIMEOUT,TimeUnit.SECONDS)
                .authenticator(tokenAuthenticator)
                .addInterceptor(tokenInterceptor)
                .dispatcher(dispatcher)
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(context.getResources().getString(R.string.base_api_url))
                .addConverterFactory(GsonConverterFactory.create(new Gson()))
                .client(okClient)
                .build();
    }


    return retrofit;
}

}

步骤2:在我的TokenAuthenticator的验证方法中:

@Override
public Request authenticate(Route route,Response response) throws IOException {
    String userRefreshToken="your refresh token";
    String cid="your client id";
    String csecret="your client secret";
    String baseUrl="your base url";

    refreshResult=refreshToken(baseUrl,userRefreshToken,cid,csecret);
    if (refreshResult) {
    //refresh is successful
    String newaccess="your new access token";

    // make current request with new access token
    return response.request().newBuilder()
            .header("Authorization",newaccess)
            .build();

    } else {
        // refresh Failed,maybe you can logout user
        // returning null is critical here,because if you do not return null 
        // it will try to refresh token continuously like 1000 times.
        // also you can try 2-3-4 times by depending you before logging out your user
        return null;
    }
}

和refreshToken方法,这只是一个例子,您可以在刷新令牌时创建自己的策略,但我使用的是最简单的连接方法HttpUrlConnection.没有缓存,没有重试只尝试连接并获得结果:

public boolean refreshToken(String url,String refresh,String cid,String csecret) throws IOException{
    URL refreshUrl=new URL(url+"token");
    HttpURLConnection urlConnection = (HttpURLConnection) refreshUrl.openConnection();
    urlConnection.setDoInput(true);
    urlConnection.setRequestMethod("POST");
    urlConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
    urlConnection.setUseCaches(false);
    String urlParameters  = "grant_type=refresh_token&client_id="+cid+"&client_secret="+csecret+"&refresh_token="+refresh;

    urlConnection.setDoOutput(true);
    DataOutputStream wr = new DataOutputStream(urlConnection.getoutputStream());
    wr.writeBytes(urlParameters);
    wr.flush();
    wr.close();

    int responseCode = urlConnection.getResponseCode();

    if(responseCode==200){
        BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
        String inputLine;
        StringBuffer response = new StringBuffer();

        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        in.close();

        // this gson part is optional,you can read response directly from Json too
        Gson gson = new Gson();
        RefreshTokenResult refreshTokenResult=gson.fromJson(response.toString(),RefreshTokenResult.class);

        // handle new token ...
        // save it to the sharedpreferences,storage bla bla ...
        return true;

    } else {
        //cannot refresh
        return false;
    } 

}

步骤3:其实我们做了,但我会显示简单的用法:

Retrofit client= RetrofitClient.getInstance();
//interface for requests
APIService service = client.create(APIService.class);
// then do your requests .....

步骤4:对于那些想要看到TokenInterceptor逻辑的人:

public class TokenInterceptor implements Interceptor{
Context ctx;
SharedPreferences mPrefs;
SharedPreferences.Editor mPrefsEdit;

public TokenInterceptor(Context ctx) {
    this.ctx = ctx;
    this.mPrefs= PreferenceManager.getDefaultSharedPreferences(ctx);
    mPrefsEdit=mPrefs.edit();
}

@Override
public Response intercept(Chain chain) throws IOException {

    Request newRequest=chain.request();

    //when saving expire time :
    integer expiresIn=response.getExpiresIn();
    Calendar c = Calendar.getInstance();
    c.add(Calendar.SECOND,expiresIn);
    mPrefsEdit.putLong("expiretime",c.getTimeInMillis());

    //get expire time from shared preferences
    long expireTime=mPrefs.getLong("expiretime",0);
    Calendar c = Calendar.getInstance();
    Date NowDate=c.getTime();
    c.setTimeInMillis(expireTime);
    Date expireDate=c.getTime();

    int result=NowDate.compareto(expireDate);
    /**
     * when comparing dates -1 means date passed so we need to refresh token
     * see {@link Date#compareto}
     */
    if(result==-1) {
        //refresh token here,and got new access token
        String newaccesstoken="newaccess";
        newRequest=chain.request().newBuilder()
                .header("Authorization",newaccesstoken)
                .build();
    }
    return chain.proceed(newRequest);
  }
}

在我的应用程序中,我正在应用程序和后台服务提出请求.他们都使用相同的实例,我可以轻松管理.请参考此答案,并尝试创建您自己的客户端.如果您仍然有以下问题,请提及我 – 另一个问题 – 或发送邮件.我有时间会帮助我希望这可以帮助.

今天关于android – Oauth 2无法交换访问令牌的代码,返回“invalid_grant”无法再进行口令登陆,尝试失败次数过多的介绍到此结束,谢谢您的阅读,有关Android Auth错误:“GetToken失败,状态码为:INVALID_AUDIENCE”、Android oauth2 无法获得 AuthToken、Android R.java令牌“int”上的语法错误,此令牌后预期的VariableDeclaratorId、Android Retrofit2刷新Oauth 2令牌等更多相关知识的信息可以在本站进行查询。

本文标签: