Tomcat やら Jetty やらといった Java アプリケーションコンテナ(Java アプリケーションサーバー)の種類に依存しない形でユーザー認証を実現するサンプル
を作ってみました。実装にはフィルタを使います。また今回は認証の種類に Basic 認証を使っています。
まずは以下のような javax.servlet.Filter インターフェースの実装となるクラス: BasicAuthenticationFilter を作ります:
また、web.xml の 内に以下の <filter> と <filter-mapping> の記述(青字部分)を追加します。この例では全ての URL (/*) に対して認証をかけるよう指定して
います:
後は確認用の index.html として適当な内容のものを用意します:
こうして作成した Java アプリケーションを動かして、ウェブブラウザからコンテキストルート(/) にアクセスすると、(初回は認証情報を付けずにアクセスする ので)作成したフィルタから 401 が返され、結果以下のような認証ダイアログが表示されるはずです:
ここに適当な内容の文字列を入力して再度アクセスすると、(今度は何かが入っていたことになるので)上記サンプルでは認証 OK という判断になり、用意した index.html が表示される、という流れが実現できます:
今回のサンプルはこちらに公開します:
https://github.com/dotnsf/BasicAuth
まずは以下のような javax.servlet.Filter インターフェースの実装となるクラス: BasicAuthenticationFilter を作ります:
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeUtility; public class BasicAuthenticationFilter implements Filter{ //. レルム名 private final String realmName = "myRealm"; //. Filter の実装に必要なメソッド(何もしない) public void init( FilterConfig config ) throws ServletException{ } public void destroy(){ } //. フィルタリング処理の実装 public void doFilter( ServletRequest req, ServletResponse res, FilterChain filterChain ) throws IOException, ServletException{ ByteArrayInputStream bin = null; BufferedReader br = null; boolean isAuthorized = false; //. この値で認証の可否を判断する try{ HttpServletRequest httpReq = ( HttpServletRequest )req; String basicAuthData = httpReq.getHeader( "authorization" ); if( basicAuthData != null && basicAuthData.length() > 6 ){ //. Basic認証から情報を取得 String basicAuthBody = basicAuthData.substring( 6 ); //. 'Basic dG9tY2F0OnRvbWNhdA== ' //. BASE64 デコード bin = new ByteArrayInputStream( basicAuthBody.getBytes() ); br = new BufferedReader( new InputStreamReader( MimeUtility.decode( bin, "base64" ) ) ); StringBuilder buf = new StringBuilder(); String line = null; while ( ( line = br.readLine() )!=null ) { buf.append( line ); } //. 入力された username と password を取り出す String[] loginInfo = buf.toString().split( ":" ); String username = loginInfo[0]; String password = loginInfo[1]; //. System.out.println( "Basic " + username + ":" + password ); //. 取り出した username と password で認証可否を判断する //. 実際にはここで LDAP やユーザー情報データベースと比較して判断することになる isAuthorized = true; //. 今回の例ではとりあえず何かが入力されていれば認証 OK とする } if( !isAuthorized ){ //. (認証に何も指定されていなかった場合も含めて)認証 NG だった場合はブラウザに UnAuthorized エラー(401)を返す HttpServletResponse httpRes = ( HttpServletResponse )res; httpRes.setHeader( "WWW-Authenticate", "Basic realm=" + this.realmName ); httpRes.setContentType( "text/html" ); httpRes.sendError( HttpServletResponse.SC_UNAUTHORIZED ); //. 401 //. 最初に認証なしでアクセスした場合はここを通るので、その結果ブラウザが認証ダイアログを出す、という流れ }else{ //. 認証 OK だった場合はそのまま処理を続ける filterChain.doFilter( req, res ); } }catch( Exception e ){ throw new ServletException( e ); }finally{ //. ストリームのクローズ try{ if( bin!=null ) bin.close(); if( br !=null ) br.close(); }catch( Exception e ){ } } } }
また、web.xml の
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>BasicAuth</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
:
:
<!-- Filter Configuration -->
<filter>
<filter-name>basicAuthFilter</filter-name>
<filter-class>me.juge.basicauth.BasicAuthenticationFilter</filter-class>
</filter>
<!-- Filter Mapping -->
<filter-mapping>
<filter-name>basicAuthFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
後は確認用の index.html として適当な内容のものを用意します:
↑超適当!<html> <head> <title>Hello</title> </head> <body> <h1>ハローワールド!</h1> </body> </html>
こうして作成した Java アプリケーションを動かして、ウェブブラウザからコンテキストルート(/) にアクセスすると、(初回は認証情報を付けずにアクセスする ので)作成したフィルタから 401 が返され、結果以下のような認証ダイアログが表示されるはずです:
ここに適当な内容の文字列を入力して再度アクセスすると、(今度は何かが入っていたことになるので)上記サンプルでは認証 OK という判断になり、用意した index.html が表示される、という流れが実現できます:
今回のサンプルはこちらに公開します:
https://github.com/dotnsf/BasicAuth