Spring rememeber-meログイン

ログインを維持してくれるremember-meログイン機能をSpring securityを用いて実装する方法を紹介します。
実装形態は次節で説明しますが、ここでは、persistence token実装形態を選択しています。

remember-me実装形態

remember-me実装形態について、以下の2つがあります。
1)cookie-base実装
remember-meクッキーにusernameとpassword(MD5hashコード)保持 1)

2)persistence token実装
persistent_loginsテーブルにランダムなserial, tokenを保持、clientのremember-meクッキーと照合します。
remember-meクッキーには一意なserialを保持していてアクセスの度にtokenを変える仕組みなのでクッキーがcaptureされてもアクセスされる可能性は低いです。
パスワードが変更になってもtokenが有効であれば使用可能です。
logoutしない限り、有効期限切れになったtokenはpersistent_loginsテーブルにレコードが残ります。
有効期限切れになったtokenを削除する機能はSpring securityに実装されてないので、自前実装が必要です。

persistent_loginsテーブル

テーブル定義SQLを下記に示します。

CREATE TABLE "PERSISTENT_LOGINS"
(	"USERNAME" VARCHAR2(100 BYTE) NOT NULL,
	"SERIES" VARCHAR2(64 BYTE),
	"TOKEN" VARCHAR2(64 BYTE) NOT NULL,
	"LAST_USED" TIMESTAMP (6) NOT NULL,
	CONSTRAINT "PERSISTENT_LOGINS_PK" PRIMARY KEY("SERIES")
)

以下はテーブルについてのメモです。
・テーブル名、カラム名は変更できない。
・同一usernameでも別端末からアクセスすると別レコード(series)が生成される。
・ログアウトするとレコードは削除される。
・同一端末でも開発環境、検証環境にrememeber-meログインする場合、2レコードが作成される。

persistent remember-me実装 必要ライブラリ

以下にpersistent rembember-me実装で必要なライブラリを示します。

ライブラリ説明
jcl-over-slf4j-1.7.36.jarspring security logging関連
log4j-slf4j-impl-2.17.1.jarspring security loggingをlog4j2.xmlにて設定可能にする
slf4j-api-1.7.32.jarspring security logging関連
spring-web-4.3.30.RELEASE.jarspring-web
spring-core-4.3.30.RELEASE.jarspring-webの依存ライブラリ
spring-aop-4.3.30.RELEASE.jarspring-webの依存ライブラリ
spring-beans-4.3.30.RELEASE.jarspring-webの依存ライブラリ
spring-context-4.3.30.RELEASE.jarspring-webの依存ライブラリ
spring-expression-4.3.30.RELEASE.jarspring-contextの依存ライブラリ
spring-jdbc-4.3.30.RELEASE.jarspring-jdbcライブラリ
spring-ldap-core-2.3.3.RELEASE.jarspring-security-ldap依存ライブラリ
spring-security-config-4.2.20.RELEASE.jarspring-security configライブラリ
spring-security-core-4.2.20.RELEASE.jarspring-security-ldap依存ライブラリ
spring-security-ldap-4.2.20.RELEASE.jarspring-secruity ldapライブラリ
spring-security-web-4.2.20.RELEASE.jarspring-security webライブラリ
spring-tx-4.3.30.RELEASE.jarspring-jdbc依存ライブラリ

実装編

以下のセクションは実装について説明します。

web.xml

web.xmlに追加する設定についてです。
下記、追加コード部分を抜粋して表示します。

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
 
	<context-param>
		<description>
		</description>
		<param-name>contextClass</param-name>
		<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
	</context-param>
	<context-param>
		<description>
		</description>
		<param-name>contextConfigLocation</param-name> ★1
		<param-value>com.contoso.web.spring</param-value>
	</context-param>
 
	<filter>
		<description>
		</description>
		<display-name>springSecurityFilterChain</display-name>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> ★2
	</filter>
        <filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<servlet-name>action</servlet-name>
	</filter-mapping>

★1
Spring Security関連Annotationが設定されているクラスのパッケージを指定します。
★2
Filter Chainの中でSpring Securityをinterceptする部分です。

PersistenceConfig.java

persitent_loginsテーブルへのデータソース接続情報を読み込ませるためのBeanを定義しているクラスになります。

package com.contoso.web.spring;
 
import javax.sql.DataSource;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
/**
 * <H3>
 * Spring Database Configuration.
 * </H3>
 * @author ri-su
 */
@Configuration
@EnableTransactionManagement
@PropertySource({"classpath:/com/contoso/base/properties/db/persistence-oracle.properties"})1
public class PersistenceConfig {
 
	@Autowired
	private Environment env;2
 
	//***** public method *****
 
	@Bean
	public DataSource dataSource() {
		final DriverManagerDataSource _dataSource = new DriverManagerDataSource();3
		_dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
		_dataSource.setUrl(env.getProperty("jdbc.url"));
		_dataSource.setUsername(env.getProperty("jdbc.user"));
		_dataSource.setPassword(env.getProperty("jdbc.pass"));
		return _dataSource;
	}
 
	//***** protected method *****
	//***** private method *****
	//***** call back method *****
	//***** getter and setter *****
 
}

★1
persistence-oracle.propertiesのパスを指定します。
★2
Springの@Autowired機能で@PropertySourceで指定したPropertiesファイルにアクセスできます。
★3
アプリ起動時にBeanインスタンス化され、後ほど説明するwebSecurityConfig.xmlからデータソースを参照できます。
参照名はメソッド名であるdataSourceです。

SecurityConfig.java

Spring security設定xmlファイル(webSecurityConfig.xml)を指定するクラスです。
WebSecurityConfigurerAdapterクラスを拡張して作成します。

package com.contoso.web.spring;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 
/**
 * <H3>
 * Spring Security Configuration.
 * </H3>
 * @author ri-su
 */
@Configuration
@ComponentScan("com.contoso.web.security")1
@EnableWebSecurity
@ImportResource({"classpath:/WEB-INF/webSecurityConfig.xml"})2
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
	//***** constructor *****
	public SecurityConfig() {
		super();
	}
 
	//***** public method *****
	//***** protected method *****
	//***** private method *****
	//***** call back method *****
	//***** getter and setter *****
 
}

☆1
webSecurityConfig.xmlからComponentとして参照したいクラスが位置しているパッケージを指定します。
☆2
webSecurityConfig.xmlのパスを指定します。

webSecurityConfig.xml

Spring security設定ファイルです。

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:sec="http://www.springframework.org/schema/security"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:jdbc="http://www.springframework.org/schema/jdbc"
  xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd">
 
	<sec:http use-expressions="true">
		<sec:intercept-url pattern="/js/**" access="permitAll" />
  		<sec:intercept-url pattern="/css/**" access="permitAll" />
    		<sec:intercept-url pattern="/images/**" access="permitAll" />
    		<sec:intercept-url pattern="/logon.do" access="permitAll" />
    		<sec:intercept-url pattern="/**" access="authenticated" />
 
		<sec:form-login login-page="/logon.do"
			login-processing-url="/logon.do"
			authentication-success-handler-ref="mySavedRequestAwareAuthenticationSuccessHandler"
			authentication-failure-url="/logon.do?error=true" /> ★1
 
		<sec:logout logout-url="/logout.do"
			success-handler-ref="simpleUrlLogoutSuccessHandler"
			delete-cookies="JSESSIONID" /> ★2
 
		<!-- 86400 Seconds = 1day -->
		<sec:remember-me authentication-success-handler-ref="rememberMeAuthenticationSuccessHandler"
			data-source-ref="dataSource"
			token-validity-seconds="2592000" /> ★3
 
		<sec:csrf disabled="true" />
	</sec:http>
 
	<!-- Persistent Remember Me Service -->
	<bean id="rememberMeAuthenticationProvider"
		class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices"> ★4
		<constructor-arg value="myAppKey" />
		<constructor-arg ref="ldapUserDetailsService" />
		<constructor-arg ref="jdbcTokenRepository" />
	</bean>
 
	<!-- Uses a database table to maintain a set of persistent login data -->
	<bean id="jdbcTokenRepository"
		class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl"> ★5
		<property name="createTableOnStartup" value="false" />
		<property name="dataSource" ref="dataSource" />
	</bean>
 
	<!-- Authentication Manager(LDAP) -->
	<sec:authentication-manager alias="authenticationManager"> ★6
		<sec:authentication-provider ref="ldapAuthProvider" />
	</sec:authentication-manager>
 
	<!-- LDAP context source -->
	<bean id="contextSource"
		class="org.springframework.security.ldap.DefaultSpringSecurityContextSource"> ★7
		<constructor-arg index="0">
			<list>
				<value>ldap://ldap001.contoso.com:3268</value>
				<value>ldap://ldap002.contoso.com:3268</value>
			</list>
		</constructor-arg>
		<constructor-arg index="1" value="dc=contoso,dc=com" />
		<property name="userDn" value="xxxxxx@contoso.com" />
		<property name="password" value="yyyyy12345" />
	</bean>
 
	<!-- LDAP authentication provider  -->
	<bean id="ldapAuthProvider"
		class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider"> ★8
		<constructor-arg>
			<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
				<constructor-arg ref="contextSource" />
				<property name="userSearch" ref="userSearch" />	
			</bean>
		</constructor-arg>
	</bean>
 
	<!-- LDAP user search  -->
	<bean id="userSearch"
		class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch"> ★9
		<constructor-arg index="0" value="" />
		<constructor-arg index="1" value="(&amp;(objectCategory=Person)(sAMAccountName={0}))" />
		<constructor-arg index="2" ref="contextSource" />
	</bean>
 
	<!-- LDAP userDetailsService  -->
	<bean id="ldapUserDetailsService"
		class="org.springframework.security.ldap.userdetails.LdapUserDetailsService"> ★10
		<constructor-arg ref="userSearch" />
		<property name="userDetailsMapper" ref="ldapUserDetailsMapper" />
	</bean>
 
	<!-- UserDetailsMapper -->
	<bean id="ldapUserDetailsMapper" class="org.springframework.security.ldap.userdetails.LdapUserDetailsMapper" />
 
	<!-- SimpleUrlLogoutSuccessHandler -->
	<bean id="simpleUrlLogoutSuccessHandler"
		class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
		<property name="useReferer" value="true" />
	</bean>
</beans>

★1
ログインUrl、ログイン成功Handlerクラス、認証失敗時の遷移Url等を設定します。
認証成功HandlerクラスであるmySavedRequestAwareAuthenticationSuccessHandlerについては後ほど説明します。

★2
ログアウトUrl、ログアウト成功Handlerクラス等を設定します。
ログアウト成功HadlerクラスはSpringのSimpleUrlLogoutSuccessHandlerを利用しています。

★3
remember-me関連設定を行います。token有効期限は秒(sec)で指定します。
SuccessHandlerについては後ほど説明します。

★4
remember-me実装形態としてpersistent token実装を設定しています。
constructorのパラメータ1に指定しているmyAppKeyはクッキーに含まれる署名に使用されるキーです。
省略する場合、SecureRandom関数でランダムに生成されますが、アプリケーション起動時に生成されるので再起動するとremember-meクッキーは全て無効になってしまいます。
アプリケーションを再起動してもクライアントが持つクッキーを有効にする場合は、任意の固定文字列を指定します。

★5
tokenを保存するデータソース関連設定を行います。
dataSourceが参照しているBeanクラスはPersistenceConfig.javaです。

★6
認証マネージャーを設定しています。

★7
ログイン時、LDAPを通して認証を行うことを設定しています。
LDAPドメインは複数指定が可能です。

★8
認証ProviderとしてLdapAuthenticationProviderを指定しています。
contextSourceには☆7を参照しています。

★9
LDAP検索方法を指定しています。Person、SAMアカウント名で検索すると指定しています。

★10
★4で設定しているLdapUserDetailsServiceについて定義しています。

MySavedRequestAwareAuthenticationSuccessHandler.java

webSecurityConfig.xmlにて参照名mySavedRequestAwareAuthenticationSuccessHandlerのクラスを以下に示します。

package com.contoso.web.security;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.ldap.userdetails.LdapUserDetails;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
 
/**
 * <H3>
 * Custom implementation of SavedRequestAwareAuthenticationSuccessHandler
 * </H3>
 * @author ri-su
 */
@Component(value = "mySavedRequestAwareAuthenticationSuccessHandler")
public class MySavedRequestAwareAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
 
	private static final Logger logger = LoggerFactory.getLogger(MySavedRequestAwareAuthenticationSuccessHandler.class);
	//ログイン画面直アクセスの場合の遷移先
	private static final String DEFAULT_TARGET_URL = "/sample/Main.do";
 
	//***** public method *****
 
	/* (non-Javadoc)
	 * @see org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler#onAuthenticationSuccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
	 */
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
			throws ServletException, IOException {1
		//authorization
		doAuthorization(request, authentication);
		//set defaultTargetUrl
		setDefaultTargetUrl(request);
		//delegate to super method
		super.onAuthenticationSuccess(request, response, authentication);
	}
 
	//***** protected method *****
	//***** private method *****
 
	//authorization
	private void doAuthorization(final HttpServletRequest request, final Authentication authentication) {
		//username
		String _username = ((LdapUserDetails)authentication.getPrincipal()).getUsername();2
		logger.debug("username: {}", _username);
 
                //do something here. 例)権限付与、セッションにユーザー情報保持
	}//doAuthorization
 
	private void setDefaultTargetUrl(final HttpServletRequest request) {
		String _targetUrl = "";
		//REQUEST_CACHEのredirectUrlをログイン画面のhiddenから取得
		String _cachedUrl = request.getParameter(REDIRECT_URL_HIDDEN_NAME);
		String _referer = request.getParameter(REFERER_URL_HIDDEN_NAME);
		logger.debug("cached redirect url: {}", _cachedUrl);
		logger.debug("referer url: {}", _referer);
		//determine targetUrl
		if (StringUtils.hasText(_referer)) {
			_targetUrl = determineTargetUrlFromReferer(_referer);
		} else if (StringUtils.hasText(_cachedUrl)) {
			_targetUrl = _cachedUrl;3
		} else {
			_targetUrl = DEFAULT_TARGET_URL;
		}
		logger.debug("target url: {}", _targetUrl);
 
		//set defaultTargetUrl
		super.setDefaultTargetUrl(_targetUrl);
		//always redirect to the value of defaultTargetUrl
		setAlwaysUseDefaultTargetUrl(true);
	}//setDefaultTargetUrl
 
        //refererUrl(ログアウト時)からtargetUrl判断
	private String determineTargetUrlFromReferer(String referer) {
		String _targetUrl = "";
		//some logic here ★4
		return _targetUrl;
	}//determineTargetUrlFromReferer
 
	//***** call back method *****
	//***** getter and setter *****
 
}

★1
onAuthenticationSuccessメソッドをオーバーライドします。
ここでは、認証成功後の権限付与(authorization)、遷移先などの設定を行います。

★2
AuthenticationからLDAP認証のusernameが取得可能です。
usernameを用いてアプリ側のauthorization処理を実装します。

★3
REQUEST_CACHEのredirectUrlをログイン画面のhiddenから取得します。
REQUEST_CACHEに残っていれば、そこに遷移します。

★4
ログアウト時のurlがログイン画面のhiddenから取得できれば、ログアウト時の画面に遷移します。

RememberMeAuthenticationSuccessHandler.java

webSecurityConfig.xmlにて参照名rememberMeAuthenticationSuccessHandlerのクラスを以下に示します。

package com.contoso.web.security;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.ldap.userdetails.LdapUserDetails;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
 
/**
 * <H3>
 * authentication-success-handler in remember-me
 * </H3>
 * @author ri-su
 */
@Component(value = "rememberMeAuthenticationSuccessHandler")
public class RememberMeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
 
	private static final Logger logger = LoggerFactory.getLogger(RememberMeAuthenticationSuccessHandler.class);
	private static final String DEFAULT_TARGET_URL = "/sample/Main.do";
	private static final String LOGON_URL = "/logon.do";
	private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
 
	//***** public method *****
 
	/* (non-Javadoc)
	 * @see org.springframework.security.web.authentication.AuthenticationSuccessHandler#onAuthenticationSuccess
	 * (javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
	 */
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
			throws IOException, ServletException {1
		handle(request, response, authentication);
		clearAuthenticationAttributes(request);
	}
 
	//***** protected method *****
 
	protected void handle(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws IOException {
		//--- determine targetUrl
		final String _targetUrl = determineTargetUrl(request);
 
		if (response.isCommitted()) {
			logger.debug("Response has already been committed. Unable to redirect to " + _targetUrl);
			return;
		}
		//authorization
		doAuthorization(request, authentication);
		redirectStrategy.sendRedirect(request, response, _targetUrl);
	}//handle
 
	/**
	 * determine target URL
	 * <br>
	 * @param request
	 * @return
	 */
	protected String determineTargetUrl(final HttpServletRequest request) {
		String _targetUrl = request.getServletPath();
		logger.debug("targetUrl: {}", _targetUrl);
		String _redirectUrl = "";
		if (!Validator.isNullOrBlank(_targetUrl) &&
			_targetUrl.indexOf(LOGON_URL) != -1) {2
		    _redirectUrl = DEFAULT_TARGET_URL;
		} else {
			_redirectUrl = _targetUrl;
		}
		return _redirectUrl;
	}//determineTargetUrl
 
      /**
       * Removes temporary authentication-related data which may have been stored in the session
       * during the authentication process.
       */
	protected final void clearAuthenticationAttributes(final HttpServletRequest request) {
		final HttpSession _session = request.getSession(false);
 
		if (_session == null) {
			return;
		}
 
		_session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
	}//clearAuthenticationAttributes
 
	//***** private method *****
 
	//authorization
	private void doAuthorization(final HttpServletRequest request, Authentication authentication) {
		//username
		String _username = ((LdapUserDetails)authentication.getPrincipal()).getUsername(); ★3
		logger.debug("username: {}", _username);
 
        //do something here. 例)権限付与、セッションにユーザー情報保持
	}//doAuthorization
 
	//***** call back method *****
	//***** getter and setter *****
 
}

★1
onAuthenticationSuccessメソッドをオーバーライドします。
ここでは、認証成功後の権限付与(authorization)、遷移先などの設定を行います。

★2
ログイン画面にアクセスする場合の遷移先を指定します。

★3
AuthenticationからLDAP認証のusernameが取得可能です。
usernameを用いてアプリ側のauthorization処理を実装します。\\をを

NewLogon.jsp

Formログイン画面の例を以下に示します。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ include file="/Taglibs.jsp" %>

<form name="f" action="${pageContext.request.contextPath}/logon.do" method="POST">
	<table>
		<tr>
			<td><bean:message key="label.mothers" /></td>
			<td><input type="text" name="username" size="9" maxlength="7"></td>
		</tr>
		<tr>
			<td><bean:message key="label.passWord" /></td>
			<td><input type="password" name="password" size="20" maxlength="25" /></td>
		</tr>
		<tr>
			<td>Remember Me:</td>
			<td><input type="checkbox" name="remember-me" /></td>
		</tr>
		<tr>
			<td><input name="submit" type="submit" value="<bean:message key='label.login' />" /></td>
		</tr>
	</table>
	<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
	<input type="hidden" name="CACHED_REQUEST_URL" value="${sessionScope.SPRING_SECURITY_SAVED_REQUEST.redirectUrl}" />
	<input type="hidden" name="REFERER_URL" value="${header['Referer']}" />
</form>

NewLogonAction.java

ログイン画面Actionの例を以下に示します。
ここではStruts1を利用したActionクラスの例です。

package com.contoso.web;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
 
/**
 * <H3>
 * Action for Remember-me Login
 * </H3>
 * @author ri-su
 */
public class NewLogonAction extends Action {
 
	//***** public method *****
 
	@Override
	public ActionForward execute(ActionMapping mapping, AbstractActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception
		if (request.getParameter("error") != null) {1
			ActionErrors _errors = new ActionErrors();
			_errors.add("username", new ActionError("errors.logon.fail"));
			saveErrors(request, _errors);
			return mapping.getInputForward();
		}
 
		return mapping.findForward(SUCCESS);
	}
 
	//***** protected method *****
	//***** private method *****
	//***** call back method *****
	//***** getter and setter *****
 
}

★1
ログインエラー発生時、エラーメッセージをActionErrorにセットして画面に表示します。

参考情報

以下セクションで参考になる情報を載せます。

Spring securityデフォルトレスポンスヘッダ

Spring remember-me実装にはSpring securityを利用していますので、Spring securityについて理解する必要があります。
Spring security XMLにて設定しなくてもデフォルトでサポートしているレスポンスヘッダをいかに示します。
・Cache-Control(Pragma, Expires)2)
・X-Frame-Options
・X-Content-Type-Options
・X-XSS-Protection
・Strict-Transport-Security3)

デフォルト値について以下の表を参照してください。

Header namevalue(default)目的
Cache-Controlno-cacheコンテンツがキャッシュされるのを防ぐため
X-Frame-OptionsDENY<iframe>に表示されるのを防ぐため
X-Content-Type-Optionslnosniffブラウザがコンテンツの種類を判断する際、コンテンツの内容を見ないようにする
X-Xss-Protection1;mode=blockXSSフィルター機能を有効にして有害なスクリプトを検知するため
1)
クッキーがcaptureされる場合、username, passwordが変わらない限り、有効期限内であれば使用可能な脆弱性があります。
2)
Spring SecurityはHTTP1.0互換のブラウザもサポートするために、PragmaヘッダとExpiresヘッダも出力する。
3)
アプリケーションサーバに対してHTTPSを使ってアクセスがあった場合のみ出力される。

コメント

コメントを入力. Wiki文法が有効です:
H A Z P W
 

QR Code
QR Code study:java:rememberme (generated for current page)