###关于wifi portal认证–为浏览器添加wifi认证功能
- 1.什么是portal认证
- 2.android的原生portal认证概要讲述
- 3.独立出portal认证到浏览器
####1.什么是portal认证
就是连接wifi成功后,有些需要去一个登录页面,登录后才能正常使用wifi。在现在商店比如肯德基,万科,万达等很多外场,都有这样的认证方式。还不清楚的百度下portal认证
####2.android的原生portal认证概要讲述
Google开发者文档 有以下讲述:
Handling Network Sign-On
Some Wi-Fi networks block Internet access until the user clicks through a sign-on page. Such sign-on pages are typically presented by using HTTP redirects. You can use getURL() to test if your connection has been unexpectedly redirected. This check is not valid until after the response headers have been received, which you can trigger by calling getHeaderFields() or getInputStream(). For example, to check that a response was not redirected to an unexpected host:
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
if (!url.getHost().equals(urlConnection.getURL().getHost())) {
// we were redirected! Kick the user out to the browser to sign on?
...
} finally {
urlConnection.disconnect();
}
}
google翻译:
处理网络点登录
一些Wi-Fi网络禁止访问Internet ,直到用户点击通过一个登录页面。这样的登录页面通常通过使用HTTP重定向呈现。您可以使用的getURL ()来测试,如果你的连接意外重定向。此检查是无效的,直到已收到响应报头之后,您可以通过调用getHeaderFields ()或的getInputStream ()触发。例如,要检查一个响应没有重定向到一个意想不到的主机:
然后在android系统中会有如下判断:
private boolean More ...isWalledGardenConnection() {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(mWalledGardenUrl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setConnectTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
urlConnection.setUseCaches(false);
urlConnection.getInputStream();
// We got a valid response, but not from the real google
return urlConnection.getResponseCode() != 204;
} catch (IOException e) {
if (DBG) {
log("Walled garden check - probably not a portal: exception " + e);
}
return false;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}
大概意思是说,那一个连接去测试,如果返回的是204 就是连接成功的,如果不是就是需要认证的,然后弹出需要认证的通知栏。点击通知,会打开,CaptivePortalLogin.apk 里面就一个activity
public class CaptivePortalLoginActivity extends Activity {
private static final String TAG = "CaptivePortalLogin";
private static final String DEFAULT_SERVER = "clients3.google.com";
private static final int SOCKET_TIMEOUT_MS = 10000;
// Keep this in sync with NetworkMonitor.
// Intent broadcast to ConnectivityService indicating sign-in is complete.
// Extras:
// EXTRA_TEXT = netId
// LOGGED_IN_RESULT = "1" if we should use network, "0" if not.
private static final String ACTION_CAPTIVE_PORTAL_LOGGED_IN =
"android.net.netmon.captive_portal_logged_in";
private static final String LOGGED_IN_RESULT = "result";
private URL mURL;
private int mNetId;
private NetworkCallback mNetworkCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String server = Settings.Global.getString(getContentResolver(), "captive_portal_server");
if (server == null) server = DEFAULT_SERVER;
try {
mURL = new URL("http://" + server + "/generate_204");
} catch (MalformedURLException e) {
done(true);
}
....
private void testForCaptivePortal() {
new Thread(new Runnable() {
public void run() {
// Give time for captive portal to open.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
HttpURLConnection urlConnection = null;
int httpResponseCode = 500;
try {
urlConnection = (HttpURLConnection) mURL.openConnection();
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setUseCaches(false);
urlConnection.getInputStream();
httpResponseCode = urlConnection.getResponseCode();
} catch (IOException e) {
} finally {
if (urlConnection != null) urlConnection.disconnect();
}
if (httpResponseCode == 204) {
done(true);
}
}
}).start();
}
private class MyWebViewClient extends WebViewClient {
private boolean firstPageLoad = true;
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (firstPageLoad) return;
testForCaptivePortal();
}
@Override
public void onPageFinished(WebView view, String url) {
if (firstPageLoad) {
firstPageLoad = false;
// Now that WebView has loaded at least one page we know it has read in the proxy
// settings. Now prompt the WebView read the Network-specific proxy settings.
setWebViewProxy();
// Load the real page.
view.loadUrl(mURL.toString());
return;
}
testForCaptivePortal();
}
}
就是用个webView去打开认证登录的网页。如果连接成功了就,发送广播,应该是去删除通知栏消息之类的操作。
####3.独立出portal认证到浏览器
将这部分功能独立出来,放到自己的浏览器中或者apk中,改怎么做呢?有两种方式
1、接收系统的intent 就是已经有系统的通知了,当用户点击通知的时候弹出自己apk中的acivity这里面需要在activity中加入如下属性,才会弹出用户选择框。
<action android:name="android.net.conn.CAPTIVE_PORTAL" />
2、不依赖系统自己做检测,自己弹出通知流程如下
public class ConnectChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent arg1) {
Intent i = new Intent(context,WifiPortalCheckService.class);
context.startService(i);
}
}
用一个接收器接收网络变化广播,然后启动个服务,在服务中做如下判断,如果连接不上就弹出通知,后面就和方案1一样了
private boolean isNeed() {
final String mWalledGardenUrl = "http://XXXX/generate_204";
final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(mWalledGardenUrl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setConnectTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
urlConnection.setUseCaches(false);
urlConnection.getInputStream();
return urlConnection.getResponseCode() != 204;
} catch (IOException e) {
return false;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}