2012-07-11 34 views
16

Tôi đang tạo một ứng dụng Android mới sử dụng SyncAdapter để xử lý đồng bộ hóa db. Tôi có mọi thứ tại chỗ và ứng dụng hoạt động tốt nhưng tôi nhận thấy rằng tôi đã đăng nhập hai lần.Đăng nhập hai lần khi sử dụng SyncAdapters

Lần đăng nhập đầu tiên diễn ra khi lớp AuthenticatorActivity (mở rộng AccountAuthenticatorActivity) xác thực người dùng và mật khẩu.

Nếu người dùng và mật khẩu là chính xác những AuthenticatorActivity sau đó thực hiện:

  • Nếu account không tồn tại nó tạo ra nó bằng cách sử mAccountManager.addAccountExplicitly()
  • Các authToken được lưu sử dụng intent.putExtra(AccountManager.KEY_AUTHTOKEN, authToken);

này về cơ bản đã được sao chép/dán từ các mẫu Android, vì vậy tôi đoán nó là ok.

Vấn đề là khi SyncAdapter ra mắt và sử dụng

authtoken = mAccountManager.blockingGetAuthToken(account, 
      AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, true); 

Phương pháp getAuthToken() bên trong lớp Authenticator kéo dài AbstractAccountAuthenticator được gọi. Và bên trong phương pháp này tôi lại nhấn điểm cuối đăng nhập một lần nữa.

Từ thời điểm đó trở đi điểm cuối đăng nhập không được nhấn lại cho đến khi authToken hết hạn.

Đây không phải là điều làm phiền tôi nhiều nhưng tôi muốn biết nếu có cách nào để tránh đăng nhập hai lần.

+0

Điều gì về việc sử dụng 'AccountManager.setAuthToken()' thay vì chuyển mã thông báo trở lại trong nhóm? – alexanderblom

+0

@alexanderblom: Tôi đã thử điều đó. Không khác nhau. – Macarse

+1

Tôi nghĩ lý do đằng sau hai lần đăng nhập là để đảm bảo mã thông báo xác thực được cập nhật, nhưng tôi không thể tìm thấy nguồn để trả lời tôi. Tôi nhớ đọc nó ở đâu đó khi tôi cố gắng làm theo ví dụ C2DM khi nó xuất hiện lần đầu vào năm ngoái trong Google I/O ... – Yenchi

Trả lời

14

Như bạn đã thấy, mặc dù Authenticator.java trong SampleSyncAdapter nói

Điều thú vị mà lớp này chứng tỏ là việc sử dụng authTokens như một phần của quá trình xác thực. ... Nếu chúng tôi đã có authToken được lưu trữ trong tài khoản, chúng tôi sẽ trả lại authToken đó. Nếu không, nhưng chúng tôi có tên người dùng và mật khẩu, sau đó chúng tôi sẽ cố gắng nói chuyện với dịch vụ mẫu để tìm nạp authToken.

đó là lời nói dối. Authenticator.getAuthToken không kiểm tra bộ nhớ cache, nó chỉ truy cập vào mạng để nhận mã thông báo.

Giải pháp là để thêm trong việc kiểm tra mất tích:

Authenticator.java: 
@Override 
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, 
     String authTokenType, Bundle loginOptions) throws NetworkErrorException { 

    // check that authToken type supported 
    ... 

    // Check if we already have a cached token to return 
    final AccountManager am = AccountManager.get(mContext); 
    String cachedAuthToken = am.peekAuthToken(account, authTokenType); 
    if (cachedAuthToken != null) { 
     final Bundle result = new Bundle(); 
     result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); 
     result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); 
     result.putString(AccountManager.KEY_AUTHTOKEN, cachedAuthToken); 
     return result; 
    } 

    // Get new authToken from server 
    ... 

    // If all else fails, prompt the user for credentials 
    ... 
} 

Lưu ý rằng phần còn lại của dự án của bạn cần phải tôn giáo sử dụng AccountManager.invalidateAuthToken khi cuộc gọi thất bại hoặc nếu không bạn sẽ gió lên với một vòng lặp vô hạn các cuộc gọi thất bại , cố gắng để có được một mã thông báo auth mới, và sau đó thất bại một lần nữa khi cùng một mã thông báo auth cache được trả về.

+2

Nếu bạn cần một ví dụ làm việc đầy đủ, tôi đã sử dụng cùng một kỹ thuật trên bộ điều hợp Sync mẫu cho bài đăng trên blog của mình về chủ đề đó. Bạn có thể xem mã ứng dụng mẫu tại đây: https://github.com/Udinic/SyncAdapter Bài đăng trên blog về bộ điều hợp đồng bộ hóa tại đây: http://udinic.wordpress.com/2013/07/24/ bạn có thể đọc ở đây: http://udinic.wordpress.com/2013/04/24/write-your-own- android-authenticator/ – Udinic

+0

trong lớp mở rộng AccountAuthenticatorActivity, tôi gọi am.setAuthToken (String) và am.setPassword (String). Trong lớp mở rộng AbstractAccountAuthenticator, tôi gọi am.peekAuthToken (tài khoản, authTokenType); Điều này trả về null lần đầu tiên. Sau đó, nó đăng nhập bằng tên người dùng từ tài khoản và mật khẩu được lưu trong trình quản lý tài khoản (am.getPassword (tài khoản)); Sau đó, tin nhắn văn bản được lưu trong trình quản lý tài khoản thông qua gói được trả về bởi getAuthToken. Bất cứ ai cũng biết tại sao am.setPassword() đặt thành công mật khẩu nhưng am.setAuthToken (String) thì không? – Ethan

Các vấn đề liên quan