AcegiSecurityで認証するAcegi Securityとは
・宣言的なセキュリティサービスを実現 機能(一部のみ抜粋)
・認証はデータベース、LDAP等に対応。 Acegi Security設定ファイルのサンプル/WEB-INF/appContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
<bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
<property name="key" value="changeThis"/>
</bean>
<bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="changeThis"/>
</bean>
</list>
</property>
</bean>
<bean id="daoAuthenticationProvider"
class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
<property name="userCache">
<bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property name="cache">
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName" value="userCache"/>
</bean>
</property>
</bean>
</property>
</bean>
<bean id="userDetailsService"
class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
<property name="usersByUsernameQuery"> ・・・・・・ ※ usersByUsernameQuery
<value>
select admin_id, password, '1'
from admin_user
where delete_date is null and admin_id = ?
</value>
</property>
<property name="authoritiesByUsernameQuery"> ・・・・・・ ※ authoritiesByUsernameQuery
<value>
select admin_id, 'ROLE_'||auth_id
from user_auth
where delete_date is null and admin_id = ?
</value>
</property>
</bean>
<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy"> ・・・・・・ ※ FilterChainProxy
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter, <-- 実際は一行で記述
logoutFilter,authenticationProcessingFilter,
securityContextHolderAwareRequestFilter,
rememberMeProcessingFilter,
anonymousProcessingFilter,
exceptionTranslationFilter,
filterInvocationInterceptor
</value>
</property>
</bean>
<bean id="httpSessionContextIntegrationFilter"
class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/index.jsp"/> <!-- URL redirected to after logout -->
<constructor-arg>
<list>
<ref bean="rememberMeServices"/>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
<bean id="authenticationProcessingFilter" ・・・・・・ ※ AuthenticationProcessingFilter
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureUrl" value="/admin/auth/LoginForm.jsp?login_error=1"/>
<property name="defaultTargetUrl" value="/"/>
<property name="filterProcessesUrl" value="/admin/auth/j_acegi_security_check"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
</bean>
<bean id="securityContextHolderAwareRequestFilter"
class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>
<bean id="rememberMeProcessingFilter"
class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
</bean>
<bean id="anonymousProcessingFilter"
class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
<property name="key" value="changeThis"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>
<bean id="exceptionTranslationFilter"
class="org.acegisecurity.ui.ExceptionTranslationFilter"> ・・・・・・ ※ ExceptionTranslationFilter
<property name="authenticationEntryPoint">
<bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/admin/auth/LoginForm.jsp"/>
<property name="forceHttps" value="false"/>
</bean>
</property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/admin/auth/failure.jsp"/>
</bean>
</property>
</bean>
<bean id="filterInvocationInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager"> ・・・・・・ ※ accessDecisionManager
<bean class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<bean class="org.acegisecurity.vote.RoleVoter"/>
<bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
</list>
</property>
</bean>
</property>
<property name="objectDefinitionSource"> ・・・・・・ ※ objectDefinitionSource
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/member/**=ROLE_member-adm
/admin/campaign/**=ROLE_campaign-adm
/admin/auth/**=IS_AUTHENTICATED_ANONYMOUSLY
</value>
</property>
</bean>
<bean id="rememberMeServices"
class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="userDetailsService"/>
<property name="key" value="changeThis"/>
</bean>
<!-- This bean is optional; it isn't used by any other bean as it only listens and logs -->
<bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener"/>
</beans>
設定内容の説明
※ usersByUsernameQuery
※ authoritiesByUsernameQuery
※ FilterChainProxy
※ AuthenticationProcessingFilter
※ ExceptionTranslationFilter
※ accessDecisionManager
※ objectDefinitionSource CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT コンテキストパス以下のパスに対して、必要なロールを定義する。 (サンプル) /secure/extreme/**=ROLE_SUPERVISOR /secure/**=IS_AUTHENTICATED_REMEMBERED /**=IS_AUTHENTICATED_ANONYMOUSLY
IS_AUTHENTICATED_REMEMBEREDは、BASE64でクッキーに保存されたユーザ web.xml設定サンプル以下は、最低限必要な設定個所のみ。
<web-app>
<!-- ContextLoaderListenerで読み込まれるBean定義ファイル。-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/appContext-security.xml
</param-value>
</context-param>
<!-- filterの設定 -->
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring ContextLoaderLister -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
ログインフォームサンプル/admin/auth/LoginForm.jsp
<%@ page contentType="text/html;charset=Shift_JIS" %>
<%@ page import="org.acegisecurity.ui.AbstractProcessingFilter" %>
<%@ page import="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter" %>
<%@ page import="org.acegisecurity.AuthenticationException" %>
<html>
<head>
<title>ログイン画面</title>
</head>
<body>
<h1>ログイン画面サンプル</h1>
Reason: <%= ((AuthenticationException) session.getAttribute
(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
<form action="j_acegi_security_check" method="POST">
<table>
<tr><td>User:</td><td><input type="text" name="j_username" size="30" ></td></tr>
<tr><td>Password:</td><td><input type="password" name="j_password"></td></tr>
<tr><td><input type="checkbox" name="_acegi_security_remember_me"></td>
<td>パスワードを保存(2週間)</td></tr>
<tr><td colspan='2'><input name="submit" type="submit"></td></tr>
<tr><td colspan='2'><input name="reset" type="reset"></td></tr>
</table>
</form>
</body>
</html>
認証処理のカスタマイズID、パスワードによる認証処理はAuthenticationProcessingFilterで行われていますが、 独自の処理を追加したい場合は、親クラスであるorg.acegisecurity.ui.AbstractProcessingFilterを継承したクラスで実装可能です。 以下のサンプルはカスタマイズされたログインID、パスワードおよびURLをパラメータで受け取り、 ログインID、パスワードで認証後にパラメータで指定したURLに遷移します。
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.AbstractProcessingFilter;
import org.apache.commons.validator.GenericValidator;
import com.powerdee.exception.CustomAuthenticationException;
public class HotspotAuthenticationProcessingFilter extends
AbstractProcessingFilter {
public static final String LOGIN_ID_KEY = "loginid";
public static final String PASSWORD_KEY = "password";
public static final String TARGET_URL = "url";
public static final String ACEGI_SECURITY_LAST_USERNAME_KEY
= "ACEGI_SECURITY_LAST_USERNAME";
public Authentication attemptAuthentication(HttpServletRequest request)
throws AuthenticationException, AccessDeniedException {
String loginId = request.getParameter(LOGIN_ID_KEY);
String password = request.getParameter(PASSWORD_KEY);
String targetUrl = request.getParameter(TARGET_URL);
// 必須パラメータチェック
if (GenericValidator.isBlankOrNull(loginId) ||
GenericValidator.isBlankOrNull(password) ||
GenericValidator.isBlankOrNull(targetUrl)) {
throw new CustomAuthenticationException("必須パラメータが設定されていません。 ");
}
// ログインID、パスワードによる認証チェック
UsernamePasswordAuthenticationToken authRequest
= new UsernamePasswordAuthenticationToken(loginId, password);
// Place the last username attempted into HttpSession for views
request.getSession().setAttribute(ACEGI_SECURITY_LAST_USERNAME_KEY, loginId);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
// 遷移先URLをセットする。
setDefaultTargetUrl(targetUrl);
return this.getAuthenticationManager().authenticate(authRequest);
}
/**
* /custom_security_checkがリクエストされると当フィルターが応答します。
*
* @return the default
*/
public String getDefaultFilterProcessesUrl() {
return "/custom_security_check";
}
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* Provided so that subclasses may configure what is put into
* the authentication request's details property.
*
* @param request that an authentication request is being created for
* @param authRequest the authentication request object that should have its details set
*/
protected void setDetails(HttpServletRequest request,
UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
}
CustomAuthenticationExceptionは、org.acegisecurity.AuthenticationExceptionを継承した独自クラスです。 認証失敗時には、この例外をスローさせると、設定ファイルで指定したauthenticationFailureUrlへフォワードされます。 フィルターの初期化処理filterChainProxyより呼び出される各フィルターはデフォルトだと、Springより生成されるためinitメソッドが実行されません。 これを回避するには、以下のようにweb.xmlでlifecycleパラメータを指定することでコンテナでのライフサイクルとなり、initメソッドも実行されるようになります。
<!-- filter -->
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
<init-param>
<param-name>lifecycle</param-name> <--このパラメータを追加する
<param-value>servlet-container-managed</param-value>
</init-param>
</filter>
おすすめ書籍
|