Docs: Training class on Identifying and Authenticating Users.
Change-Id: Ie2005687ca3baf28d9e01be8c10ee0f6a58a3cc3
This commit is contained in:
253
docs/html/training/id-auth/authenticate.jd
Normal file
253
docs/html/training/id-auth/authenticate.jd
Normal file
@@ -0,0 +1,253 @@
|
||||
page.title=Authenticating to OAuth2 Services
|
||||
parent.title=Identifying and Authenticating Users
|
||||
parent.link=index.html
|
||||
|
||||
trainingnavtop=true
|
||||
previous.title=Identifying Your User
|
||||
previous.link=identify.html
|
||||
next.title=Creating a Custom Account Type
|
||||
next.link=custom_auth.html
|
||||
|
||||
@jd:body
|
||||
|
||||
<!-- This is the training bar -->
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#Gather">Gather Information</a></li>
|
||||
<li><a href="#RequestToken">Request an Auth Token</a></li>
|
||||
<li><a href="#RequestAgain">Request an Auth Token... Again</a></li>
|
||||
<li><a href="#ConnectToService">Connect to the Online Service</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>In order to securely access an online service, users need to authenticate to
|
||||
the service—they need to provide proof of their identity. For an
|
||||
application that accesses a third-party service, the security problem is even
|
||||
more complicated. Not only does the user need to be authenticated to access the
|
||||
service, but the application also needs to be authorized to act on the user's
|
||||
behalf. </p>
|
||||
|
||||
<p>The industry standard way to deal with authentication to third-party services
|
||||
is the OAuth2 protocol. OAuth2 provides a single value, called an <strong>auth
|
||||
token</strong>, that represents both the user's identity and the application's
|
||||
authorization to act on the user's behalf. This lesson demonstrates connecting
|
||||
to a Google server that supports OAuth2. Although Google services are used as an
|
||||
example, the techniques demonstrated will work on any service that correctly
|
||||
supports the OAuth2 protocol.</p>
|
||||
|
||||
<p>Using OAuth2 is good for:</p>
|
||||
<ul>
|
||||
<li>Getting permission from the user to access an online service using his or
|
||||
her account.</li>
|
||||
<li>Authenticating to an online service on behalf of the user.</li>
|
||||
<li>Handling authentication errors.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="Gather">Gather Information</h2>
|
||||
|
||||
<p>To begin using OAuth2, you need to know a few things about the API you're trying
|
||||
to access:</p>
|
||||
|
||||
<ul>
|
||||
<li>The url of the service you want to access.</li>
|
||||
<li>The <strong>auth scope</strong>, which is a string that defines the specific
|
||||
type of access your app is asking for. For instance, the auth scope for
|
||||
read-only access to Google Tasks is <code>View your tasks</code>, while the auth
|
||||
scope for read-write access to Google Tasks is <code>Manage Your
|
||||
Tasks</code>.</li>
|
||||
<li>A <strong>client id</strong> and <strong>client secret</strong>, which are
|
||||
strings that identify your app to the service. You need to obtain these strings
|
||||
directly from the service owner. Google has a self-service system for obtaining
|
||||
client ids and secrets. The article <a
|
||||
href="http://code.google.com/apis/tasks/articles/oauth-and-tasks-on-android.
|
||||
html">Getting Started with the Tasks API and OAuth 2.0 on Android</a> explains
|
||||
how to use this system to obtain these values for use with the Google Tasks
|
||||
API.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="RequestToken">Request an Auth Token</h2>
|
||||
|
||||
<p>Now you're ready to request an auth token. Auth tokens usually expire after
|
||||
some period of time, so you'll have to renew them.</p>
|
||||
|
||||
<!-- TODO: I think a flowchart would be useful here, or perhaps a link to an as-yet-to-be-created
|
||||
flowchart that lives in the docs. -->
|
||||
|
||||
<p>To get an auth token you first need to request the
|
||||
{@link android.Manifest.permission#ACCOUNT_MANAGER}
|
||||
to yourmanifest file. To actually do anything useful with the
|
||||
token, you'll also need to add the {@link android.Manifest.permission#INTERNET}
|
||||
permission.</p>
|
||||
|
||||
<code>
|
||||
<manifest ... >
|
||||
<uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
...
|
||||
</manifest>
|
||||
</code>
|
||||
|
||||
|
||||
<p>Once your app has these permissions set, you can call {@link
|
||||
android.accounts.AccountManager#getAuthToken AccountManager.getAuthToken()} to get the
|
||||
token.</p>
|
||||
|
||||
<p>Watch out! Calling methods on {@link android.accounts.AccountManager} can be tricky! Since
|
||||
account operations may involve network communication, most of the {@link
|
||||
android.accounts.AccountManager} methods are asynchronous. This means that instead of doing all of
|
||||
your auth work in one function, you need to implement it as a series of callbacks. For example:</p>
|
||||
|
||||
<pre>
|
||||
AccountManager am = AccountManager.get(this);
|
||||
Bundle options = new Bundle();
|
||||
|
||||
am.getAuthToken(
|
||||
myAccount_, // Account retrieved using getAccountsByType()
|
||||
"Manage your tasks", // Auth scope
|
||||
options, // Authenticator-specific options
|
||||
this, // Your activity
|
||||
new OnTokenAcquired(), // Callback called when a token is successfully acquired
|
||||
new Handler(new OnError())); // Callback called if an error occurs
|
||||
</pre>
|
||||
|
||||
<p>In this example, <code>OnTokenAcquired</code> is a class that extends
|
||||
{@link android.accounts.AccountManagerCallback}. {@link android.accounts.AccountManager} calls
|
||||
{@link android.accounts.AccountManagerCallback#run run()} on <code>OnTokenAcquired</code> with an
|
||||
{@link android.accounts.AccountManagerFuture} that contains a {@link android.os.Bundle}. If
|
||||
the call succeeded, the token is inside
|
||||
the {@link android.os.Bundle}.</p>
|
||||
|
||||
<p>Here's how you can get the token from the {@link android.os.Bundle}:</p>
|
||||
|
||||
<pre>
|
||||
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
|
||||
@Override
|
||||
public void run(AccountManagerFuture<Bundle> result) {
|
||||
// Get the result of the operation from the AccountManagerFuture.
|
||||
Bundle bundle = result.getResult();
|
||||
|
||||
// The token is a named value in the bundle. The name of the value
|
||||
// is stored in the constant AccountManager.KEY_AUTHTOKEN.
|
||||
token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
|
||||
...
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>If all goes well, the {@link android.os.Bundle} contains a valid token in the {@link
|
||||
android.accounts.AccountManager#KEY_AUTHTOKEN} key and you're off to the races. Things don't
|
||||
always go that smoothly, though...</p>
|
||||
|
||||
|
||||
<h2 id="RequestAgain">Request an Auth Token... Again</h2>
|
||||
|
||||
<p>Your first request for an auth token might fail for several reasons:</p>
|
||||
|
||||
<ul>
|
||||
<li>An error in the device or network caused {@link android.accounts.AccountManager} to fail.</li>
|
||||
<li>The user decided not to grant your app access to the account.</li>
|
||||
<li>The stored account credentials aren't sufficient to gain access to the account.</li>
|
||||
<li>The cached auth token has expired.</li>
|
||||
</ul>
|
||||
|
||||
<p>Applications can handle the first two cases trivially, usually by simply
|
||||
showing an error message to the user. If the network is down or the user decided
|
||||
not to grant access, there's not much that your application can do about it. The
|
||||
last two cases are a little more complicated, because well-behaved applications
|
||||
are expected to handle these failures automatically.</p>
|
||||
|
||||
<p>The third failure case, having insufficient credentials, is communicated via the {@link
|
||||
android.os.Bundle} you receive in your {@link android.accounts.AccountManagerCallback}
|
||||
(<code>OnTokenAcquired</code> from the previous example). If the {@link android.os.Bundle} includes
|
||||
an {@link android.content.Intent} in the {@link android.accounts.AccountManager#KEY_INTENT} key,
|
||||
then the authenticator is telling you that it needs to interact directly with the user before it can
|
||||
give you a valid token.</p>
|
||||
|
||||
<p>There may be many reasons for the authenticator to return an {@link android.content.Intent}. It
|
||||
may be the first time the user has logged in to this account. Perhaps the user's account has expired
|
||||
and they need to log in again, or perhaps their stored credentials are incorrect. Maybe the account
|
||||
requires two-factor authentication or it needs to activate the camera to do a retina scan. It
|
||||
doesn't really matter what the reason is. If you want a valid token, you're going to have to fire
|
||||
off the {@link android.content.Intent} to get it.</p>
|
||||
|
||||
<pre>
|
||||
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
|
||||
@Override
|
||||
public void run(AccountManagerFuture<Bundle> result) {
|
||||
...
|
||||
Intent launch = (Intent) result.get(AccountManager.KEY_INTENT);
|
||||
if (launch != null) {
|
||||
startActivityForResult(launch, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Note that the example uses {@link android.app.Activity#startActivityForResult
|
||||
startActivityForResult()}, so that you can capture
|
||||
the result of the {@link android.content.Intent} by implementing {@link
|
||||
android.app.Activity#onActivityResult onActivityResult()} in
|
||||
your own activity. This is important! If you don't capture the result from the
|
||||
authenticator's response {@link android.content.Intent},
|
||||
it's impossible to tell whether the user has successfully authenticated or not.
|
||||
If the result is {@link android.app.Activity#RESULT_OK}, then the
|
||||
authenticator has updated the stored credentials so that they are sufficient for
|
||||
the level of access you requested, and you should call {@link
|
||||
android.accounts.AccountManager#getAuthToken AccountManager.getAuthToken()} again to request the new
|
||||
auth token.</p>
|
||||
|
||||
<p>The last case, where the token has expired, it is not actually an {@link
|
||||
android.accounts.AccountManager} failure. The only way to discover whether a token is expired or not
|
||||
is to contact the server, and it would be wasteful and expensive for {@link
|
||||
android.accounts.AccountManager} to continually go online to check the state of all of its tokens.
|
||||
So this is a failure that can only be detected when an application like yours tries to use the auth
|
||||
token to access an online service.</p>
|
||||
|
||||
|
||||
<h2 id="ConnectToService">Connect to the Online Service</h2>
|
||||
|
||||
<p>The example below shows how to connect to a Google server. Since Google uses the
|
||||
industry standard OAuth2 protocol to
|
||||
authenticate requests, the techniques discussed here are broadly
|
||||
applicable. Keep in mind, though, that every
|
||||
server is different. You may find yourself needing to make minor adjustments to
|
||||
these instructions to account for your specific
|
||||
situation.</p>
|
||||
|
||||
<p>The Google APIs require you to supply four values with each request: the API
|
||||
key, the client ID, the client secret,
|
||||
and the auth key. The first three come from the Google API Console
|
||||
website. The last is the string value you
|
||||
obtained by calling {@link android.accounts.AccountManager#getAuthToken(android.accounts.Account,java.lang.String,android.os.Bundle,android.app.Activity,android.accounts.AccountManagerCallback,android.os.Handler) AccountManager.getAuthToken()}. You pass these to the
|
||||
Google Server as part of
|
||||
an HTTP request.</p>
|
||||
|
||||
<pre>
|
||||
URL url = new URL("https://www.googleapis.com/tasks/v1/users/@me/lists?key=" + <em>your_api_key</em>);
|
||||
URLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.addRequestProperty("client_id", <em>your client id</em>);
|
||||
conn.addRequestProperty("client_secret", <em>your client secret</em>);
|
||||
conn.setRequestProperty("Authorization", "OAuth " + token);
|
||||
</pre>
|
||||
|
||||
<p>If the request returns
|
||||
an HTTP error code of 401, then your token has been denied. As mentioned in the
|
||||
last section, the most common reason for
|
||||
this is that the token has expired. The fix is
|
||||
simple: call
|
||||
{@link android.accounts.AccountManager#invalidateAuthToken AccountManager.invalidateAuthToken()} and
|
||||
repeat the token acquisition dance one
|
||||
more time.</p>
|
||||
|
||||
<p>Because expired tokens are such a common occurrence, and fixing them is so easy, many
|
||||
applications just assume the token has expired before even asking for it. If renewing a token is a
|
||||
cheap operation for your server, you might prefer to call {@link
|
||||
android.accounts.AccountManager#invalidateAuthToken AccountManager.invalidateAuthToken()} before the
|
||||
first call to {@link android.accounts.AccountManager#getAuthToken AccountManager.getAuthToken()},
|
||||
and spare yourself the need to request an auth token twice.</p>
|
||||
185
docs/html/training/id-auth/custom_auth.jd
Normal file
185
docs/html/training/id-auth/custom_auth.jd
Normal file
@@ -0,0 +1,185 @@
|
||||
page.title=Creating a Custom Account Type
|
||||
parent.title=Identifying and Authenticating Users
|
||||
parent.link=index.html
|
||||
|
||||
trainingnavtop=true
|
||||
previous.title=Authenticating to OAuth2 Services
|
||||
previous.link=authenticate.html
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#AccountCode">Implement Your Custom Account Code</a></li>
|
||||
<li><a href="#Security">Be Smart About Security!</a></li>
|
||||
<li><a href="#ExtendThatThing">Extend AbstractAccountAuthenticator</a></li>
|
||||
<li><a href="#TaskFour">Create an Authenticator Service</a></li>
|
||||
<li><a href="#DistributeService">Distribute Your Service</a></li>
|
||||
</ol>
|
||||
|
||||
<h2>You should also read</h2>
|
||||
<ul>
|
||||
<li><a
|
||||
href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
|
||||
SampleSyncAdapter app</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>In the previous lessons, we've talked about using Google accounts to identify Google users and
|
||||
access Google APIs. But what if you've got your own online service? It turns out
|
||||
to be relatively straightforward to install new account types on a user's
|
||||
device. This lesson explains how to create a custom account type that works the
|
||||
same way as the built-in accounts do. </p>
|
||||
|
||||
|
||||
<h2 id="AccountCode">Implement Your Custom Account Code</h2>
|
||||
|
||||
<p>The first thing you'll need is a way to get credentials from the user. This
|
||||
may be as simple as a dialog box that asks for a name and a password. Or it may
|
||||
be a more exotic procedure like a one-time password or a biometric scan. Either
|
||||
way, it's your responsibility to implement the code that:</p>
|
||||
<ol>
|
||||
<li>Collects credentials from the user</li>
|
||||
<li>Authenticates the credentials with the server</li>
|
||||
<li>Stores the credentials on the device</li>
|
||||
</ol>
|
||||
|
||||
|
||||
<p>Typically all three of these requirements can be handled by one activity. We'll call this the
|
||||
authenticator activity.</p>
|
||||
|
||||
<p>Because they need to interact with the {@link android.accounts.AccountManager} system,
|
||||
authenticator activities have certain requirements that normal activities don't. To make it easy to
|
||||
get things right, the Android framework supplies a base class, {@link
|
||||
android.accounts.AccountAuthenticatorActivity}, which you can extend to create your own custom
|
||||
authenticator.</p>
|
||||
|
||||
<p>How you address the first two requirements of an authenticator activity,
|
||||
credential collection and authentication, is completely up to you. (If there
|
||||
were only one way to do it, there'd be no need for "custom" account types, after
|
||||
all.) The third requirement has a canonical, and rather simple,
|
||||
implementation:</p>
|
||||
|
||||
<pre>
|
||||
final Account account = new Account(mUsername, <em>your_account_type</em>);
|
||||
mAccountManager.addAccountExplicitly(account, mPassword, null);
|
||||
</pre>
|
||||
|
||||
|
||||
<h2 id="Security">Be Smart About Security!</h2>
|
||||
|
||||
<p>It's important to understand that {@link android.accounts.AccountManager} is not an encryption
|
||||
service
|
||||
or a keychain. It stores account credentials just as you pass them, in <strong>plain
|
||||
text</strong>. On most devices, this isn't
|
||||
a particular concern, because it stores them in
|
||||
a database that is only accessible to root. But on a rooted device, the
|
||||
credentials would be readable by anyone with {@code adb} access to the device.</p>
|
||||
|
||||
<p>With this in mind, you shouldn't pass the user's actual
|
||||
password to {@link android.accounts.AccountManager#addAccountExplicitly
|
||||
AccountManager.addAccountExplicitly()}. Instead, you should store a
|
||||
cryptographically secure token that would be of limited use to an attacker. If your
|
||||
user credentials are protecting something valuable, you should carefully
|
||||
consider doing something similar.</p>
|
||||
|
||||
<p class="caution"><strong>Remember:</strong> When it comes to security code, follow the
|
||||
"Mythbusters" rule: don't try this at home! Consult a security professional before implementing any
|
||||
custom account code.</p>
|
||||
|
||||
<p>Now that the security disclaimers are out of the way, it's time to get back to work.
|
||||
You've already implemented the meat of your custom account code; what's left is
|
||||
plumbing.</p>
|
||||
|
||||
|
||||
<h2 id="ExtendThatThing">Extend AbstractAccountAuthenticator</h2>
|
||||
|
||||
<p>In order for the {@link android.accounts.AccountManager} to work with your custom account
|
||||
code, you
|
||||
need a class that implements the interfaces that {@link android.accounts.AccountManager} expects.
|
||||
This class is the <em>authenticator class</em>.</p>
|
||||
|
||||
<p>The easiest way to create an authenticator class is to extend
|
||||
{@link android.accounts.AbstractAccountAuthenticator} and implement its abstract methods. If you've
|
||||
worked through the previous lessons, the abstract methods of
|
||||
{@link android.accounts.AbstractAccountAuthenticator} should look familiar: they're the opposite
|
||||
side of
|
||||
the methods you called in the previous lesson to get account information and
|
||||
authorization tokens.</p>
|
||||
|
||||
<p>Implementing an authenticator class properly requires a number of separate
|
||||
pieces of code. First, {@link android.accounts.AbstractAccountAuthenticator} has seven abstract
|
||||
methods that you must override. Second, you need to add an
|
||||
<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filter</a> for
|
||||
<code>"android.accounts.AccountAuthenticator"</code> to your application
|
||||
manifest (shown in the next section). Finally, you must supply two XML resources that define, among
|
||||
other
|
||||
things, the name of your custom account type and the icon that the system will
|
||||
display next to accounts of this type.</p>
|
||||
|
||||
<p> You can find a step-by-step guide to implementing a successful authenticator class and the XML
|
||||
files in the {@link android.accounts.AbstractAccountAuthenticator} documentation. There's also a
|
||||
sample implementation in the <a
|
||||
href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
|
||||
SampleSyncAdapter sample app</a>.</p>
|
||||
|
||||
<p>As you read through the SampleSyncAdapter code, you'll notice that several of
|
||||
the methods return an intent in a bundle. This is the same intent that will be
|
||||
used to launch your custom authenticator activity. If your authenticator
|
||||
activity needs any special initialization parameters, you can attach them to the
|
||||
intent using {@link android.content.Intent#putExtra Intent.putExtra()}.</p>
|
||||
|
||||
|
||||
<h2 id="TaskFour">Create an Authenticator Service</h2>
|
||||
|
||||
<p>Now that you have an authenticator class, you need a place for it to live.
|
||||
Account authenticators need to be available to multiple applications and work in
|
||||
the background, so naturally they're required to run inside a {@link android.app.Service}. We'll
|
||||
call this the authenticator service.</p>
|
||||
|
||||
<p>Your authenticator service can be very simple. All it needs to do is create
|
||||
an instance of your authenticator class in {@link android.app.Service#onCreate onCreate()} and call
|
||||
{@link android.accounts.AbstractAccountAuthenticator#getIBinder getIBinder()} in {@link
|
||||
android.app.Service#onBind onBind()}. The <a
|
||||
href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
|
||||
SampleSyncAdapter</a> contains a good example of an authenticator service.</p>
|
||||
|
||||
<p>Don't forget to add a {@code <service>} tag to your manifest file
|
||||
and add an intent filter for the AccountAuthenticator intent and declare the account
|
||||
authenticator:</p>
|
||||
|
||||
<pre>
|
||||
<service ...>
|
||||
<intent-filter>
|
||||
<action android:name="android.accounts.AccountAuthenticator" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator" />
|
||||
</service>
|
||||
</pre>
|
||||
|
||||
|
||||
<h2 id="DistributeService">Distribute Your Service</h2>
|
||||
|
||||
<p>You're done! The system now recognizes your account type, right alongside all
|
||||
the big name account types like "Google" and "Corporate." You can use the
|
||||
<strong>Accounts & Sync</strong> Settings page to add an account, and apps that ask for
|
||||
accounts of your custom type will be able to enumerate and authenticate just as
|
||||
they would with any other account type.</p>
|
||||
|
||||
<p>Of course, all of this assumes that your account service is actually
|
||||
installed on the device. If only one app will ever access the service, then
|
||||
this isn't a big deal—just bundle the service in the app.
|
||||
But if you want your account service to be used by more than one app, things get
|
||||
trickier. You don't want to bundle the service with all of your apps and have
|
||||
multiple copies of it taking up space on your user's device.</p>
|
||||
|
||||
<p>One solution is to place the service in one small, special-purpose APK. When
|
||||
an app wishes to use your custom account type, it can check the device to see if
|
||||
your custom account service is available. If not, it can direct the user to
|
||||
Android Market to download the service. This may seem like a great deal of
|
||||
trouble at first, but compared with the alternative of re-entering credentials
|
||||
for every app that uses your custom account, it's refreshingly easy.</p>
|
||||
137
docs/html/training/id-auth/identify.jd
Normal file
137
docs/html/training/id-auth/identify.jd
Normal file
@@ -0,0 +1,137 @@
|
||||
page.title=Identifying Your User
|
||||
parent.title=Identifying and Authenticating Users
|
||||
parent.link=index.html
|
||||
|
||||
trainingnavtop=true
|
||||
next.title=Authenticating to OAuth2 Services
|
||||
next.link=authenticate.html
|
||||
|
||||
@jd:body
|
||||
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#ForYou">Determine if AccountManager for You</a></li>
|
||||
<li><a href="#TaskTwo">Decide What Type of Account to Use</a></li>
|
||||
<li><a href="#GetPermission">Request GET_ACCOUNT permission</a></li>
|
||||
<li><a href="#TaskFive">Query AccountManager for a List of Accounts</a></li>
|
||||
<li><a href="#IdentifyUser">Use the Account Object to Identify the User</a></li>
|
||||
<li><a href="#IdIsEnough">Decide Whether Identification is Enough</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<p>Everyone likes it when you remember their name. One of the simplest, most
|
||||
effective things you can do to make your app more lovable is to remember who
|
||||
your user is—especially when the user upgrades to a new device or starts carrying
|
||||
a tablet as well as a phone. But how do you know who your user is? And how do
|
||||
you recognize them on a new device?</p>
|
||||
|
||||
<p>For many applications, the answer is the {@link android.accounts.AccountManager} APIs. With the
|
||||
user's permission, you can use Account Manager to uniquely identify a user
|
||||
by the online identity that the user has stored on their device.</p>
|
||||
|
||||
<p>Integration with the user's accounts allows you to do a variety of things such as:</p>
|
||||
<ul>
|
||||
<li>Auto-fill forms with the user's email address.</li>
|
||||
<li>Retrieve an ID that is tied to a user, not the device.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="ForYou">Determine if AccountManager for You</h2>
|
||||
|
||||
<p>Applications typically identify the user in three different ways:</p>
|
||||
<ol type="a">
|
||||
<li>Ask the user to type in a username </li>
|
||||
<li>Use a unique device identifier rather than a user identifier</li>
|
||||
<li>Retrieve a built-in account from {@link android.accounts.AccountManager}</li>
|
||||
</ol>
|
||||
|
||||
<p>Option (a) is problematic. First, asking the user to type something before
|
||||
entering your app will automatically make your app less appealing. Second,
|
||||
there's no guarantee that the username chosen will be unique. </p>
|
||||
|
||||
<p>Option (b) is less onerous for the user, but it's
|
||||
<a href="http://android-developers.blogspot.com/2011/03/identifying-app-installations.html">tricky
|
||||
to get right</a>. More
|
||||
importantly, it only allows you to remember the user on one device. Imagine the
|
||||
frustration of someone who upgrades to a shiny new device, only to find that
|
||||
your app no longer remembers them.</p>
|
||||
|
||||
<p>Option (c) is the preferred technique. Account Manager allows you to get
|
||||
information about the accounts that are stored on the user's device. As we'll
|
||||
see in this lesson, using Account Manager lets you identify your user, no matter
|
||||
how many devices the user may own, by adding just a couple of extra taps to your
|
||||
UI.</p>
|
||||
|
||||
|
||||
<h2 id="TaskTwo">Decide What Type of Account to Use</h2>
|
||||
|
||||
<p>Android devices can store multiple accounts from many different providers.
|
||||
When you query {@link android.accounts.AccountManager} for account names, you can choose to filter
|
||||
by
|
||||
account type. The account type is a string that uniquely identifies the entity
|
||||
that issued the account. For instance, Google accounts have type "com.google,"
|
||||
while Twitter uses "com.twitter.android.auth.login."</p>
|
||||
|
||||
|
||||
<h2 id="GetPermission">Request GET_ACCOUNT permission</h2>
|
||||
|
||||
<p>In order to get a list of accounts on the device, your app needs the {@link
|
||||
android.Manifest.permission#GET_ACCOUNTS}
|
||||
permission. Add a <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code
|
||||
<uses-permission>}</a> tag in your manifest file to request
|
||||
this permission:</p>
|
||||
|
||||
<pre>
|
||||
<manifest ... >
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
...
|
||||
</manifest>
|
||||
</pre>
|
||||
|
||||
|
||||
<h2 id="TaskFive">Query AccountManager for a List of Accounts</h2>
|
||||
|
||||
<p>Once you decide what account type you're interested in, you need to query for accounts of that
|
||||
type. Get an instance of {@link android.accounts.AccountManager} by calling {@link
|
||||
android.accounts.AccountManager#get(android.content.Context) AccountManager.get()}. Then use that
|
||||
instance to call {@link android.accounts.AccountManager#getAccountsByType(java.lang.String)
|
||||
getAccountsByType()}.</p>
|
||||
|
||||
<pre>
|
||||
AccountManager am = AccountManager.get(this); // "this" references the current Context
|
||||
|
||||
Account[] accounts = am.getAccountsByType("com.google");
|
||||
</pre>
|
||||
|
||||
<p>This returns an array of {@link android.accounts.Account} objects. If there's more than one
|
||||
{@link android.accounts.Account} in
|
||||
the array, you should present a dialog asking the user to select one.</p>
|
||||
|
||||
|
||||
<h2 id="IdentifyUser">Use the Account Object to Identify the User</h2>
|
||||
|
||||
<p>The {@link android.accounts.Account} object contains an account name, which for Google accounts
|
||||
is an
|
||||
email address. You can use this information in several different ways, such as:
|
||||
<ul>
|
||||
<li> As suggestions in forms, so the user doesn't need to input account information by
|
||||
hand.</li>
|
||||
<li> As a key into your own online database of usage and personalization information.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="IdIsEnough">Decide Whether Identification is Enough</h2>
|
||||
|
||||
<p>Account names are a good way to identify the user, but the {@link android.accounts.Account}
|
||||
object by
|
||||
itself doesn't protect your data or give you access to anything. If you intend
|
||||
to access private data, you'll need something stronger: authentication.
|
||||
The next lesson explains how to authenticate to existing online services. The lesson after that
|
||||
deals with writing a custom authenticator so that you can install your own
|
||||
account types.</p>
|
||||
65
docs/html/training/id-auth/index.jd
Normal file
65
docs/html/training/id-auth/index.jd
Normal file
@@ -0,0 +1,65 @@
|
||||
page.title=Identifying and Authenticating Users
|
||||
|
||||
trainingnavtop=true
|
||||
startpage=true
|
||||
next.title=Identifying Your User
|
||||
next.link=identify.html
|
||||
|
||||
@jd:body
|
||||
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
|
||||
<h2>Requirements and prerequisites</h2>
|
||||
<ul>
|
||||
<li>Android 2.0 (API level 5) or higher</li>
|
||||
<li>Experience with <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a></li>
|
||||
<li>Experience with <a href="http://oauth.net/2/">OAuth 2.0</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>You should also read</h2>
|
||||
<ul>
|
||||
<li><a
|
||||
href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
|
||||
SampleSyncAdapter app</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<p>Android users get attached to their devices and to applications that they
|
||||
love. One way to make your application lovable is to make it personal. Android
|
||||
devices know who your user is, what services they have access to, and where they
|
||||
store your data. With your user's permission, you can use that information to
|
||||
make your application a richer, more personal experience.</p>
|
||||
|
||||
<p>In this class, you will learn multiple techniques for interacting with your
|
||||
user's identity, enabling you to:</p>
|
||||
|
||||
<ul>
|
||||
<li>Identify the user by detecting and selecting an account
|
||||
<li>Authenticate the user to make sure they are who they say they are
|
||||
<li>Gain permission to access the user's online data via services like
|
||||
the Google APIs
|
||||
<li>Add a custom account to the user's device to authenticate your own
|
||||
back-end services
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Lessons</h2>
|
||||
|
||||
<dl>
|
||||
<dt><b><a href="identify.html">Identifying Your User</a></b></dt>
|
||||
<dd>Use {@link android.accounts.AccountManager} to learn the user's account name(s).</dd>
|
||||
|
||||
<dt><b><a href="authenticate.html">Authenticating to OAuth2 Services</a></b></dt>
|
||||
<dd> Use OAuth2 to help users get permission to access web services without needing to type in a
|
||||
login name or password. </dd>
|
||||
|
||||
<dt><b><a href="custom_auth.html">Creating a Custom Account Type</a></b></dt>
|
||||
<dd>Add your own account type to the Android Account Manager.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
Reference in New Issue
Block a user