はじめに
Spring Securityを使ってデータベースに保存されたユーザ、パスワードでログインする機能を作ってみたいと思います。
Spring Securityで規定されたusersテーブルのスキーマをそのまま使う分には、
Springの定義ファイルを編集するするだけでよいのですが
このusersテーブルに他の項目を追加してログインセッションに置きたい場合は、カスタマイズが必要になります。
ログインが成功した場合、セッションキー「SPRING_SECURITY_CONTEXT」にusersテーブルの情報が置かれます。
カスタマイズとしては、UserDetailsインターフェイス(org.springframework.security.core.userdetails)実装クラスと
UserDetailsServiceインターフェイス(org.springframework.security.core.userdetails)実装クラスの作成になります。
UserDetailsインターフェイス実装クラスは、ログイン成功時、セッションに置かれるログインユーザ情報を保持するクラスです。
今回は、EntityBeanで作成します。
UserDetailsServiceインターフェイス実装クラスは、ユーザ情報取得メソッド(loadUserByUsername)を実装します。
今回は、EntityManagerを使ってユーザ情報を取得します。
今回は、usersテーブルに連絡先(contact)を追加したいと思います。
ではでは!Getting Started!!
環境
OS | Windows XP |
---|---|
データベース | MySQL 5.5.8 |
アプリケーションサーバー | Tomcat 7.0.27 |
Java | JDK 1.7.0 |
フレームワーク | Spring Framework 3.1.0.RELEASE |
Spring Security 3.1.0.RELEASE | |
Hibernate 3.6.10.Final | |
ビルドツール | Maven 3.0.4 ※mvnコマンドが実行できるように設定しておきます。 |
「3.1.0.RELEASE」でMavenビルドすると「invalid LOC header」エラーなるものが 発生していたのですが、Springframeworkのローカルのリポジトリ「C:\Documents and Settings\{user}\.m2\repository\org\springframework」を削除して 再度ビルドするとうまくいきました。
プロジェクト構成
Cドライブ直下に「studying-spring-security」フォルダを作成し各ファイルを以下のように配置します。
Spring Rooでプロジェクトを作成し、今回使わないもの(Tiles、Themeなど)を削除しました。
データベースの作成
1 2 | DROP DATABASE IF EXISTS studying_spring_security; CREATE DATABASE IF NOT EXISTS studying_spring_security DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; |
※データベースユーザとして、パスワードなしのrootユーザが作成してあるとします。
テーブルの作成とログインユーザの登録
ログインユーザとして、adminとuserを作成します。
ログインID/パスワードはそれぞれ
admin/admin、user/user
としています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `username` varchar (50) NOT NULL , ` password ` varchar (255) NOT NULL , `enabled` tinyint(1) NOT NULL , `contact` varchar (255) DEFAULT NULL , PRIMARY KEY (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `authorities`; CREATE TABLE `authorities` ( `username` varchar (50) NOT NULL , `authority` varchar (50) NOT NULL , UNIQUE KEY `ix_auth_username` (`username`,`authority`), CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `persistent_logins`; CREATE TABLE `persistent_logins` ( `username` varchar (64) NOT NULL , `series` varchar (64) NOT NULL , `token` varchar (64) NOT NULL , `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`series`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `users` VALUES ( 'admin' , '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918' , '1' , 'admin@mydomain.com' ); INSERT INTO `users` VALUES ( 'user' , '04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb' , '1' , 'user@mydomain.com' ); INSERT INTO `authorities` VALUES ( 'admin' , 'ROLE_ADMIN' ); INSERT INTO `authorities` VALUES ( 'admin' , 'ROLE_USER' ); INSERT INTO `authorities` VALUES ( 'user' , 'ROLE_USER' ); |
ServletとLoggerの設定
web.xml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | <? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?> < web-app version = "3.0" xmlns = "http://java.sun.com/xml/ns/javaee" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd "> < display-name >studying-spring-security</ display-name > < context-param > < param-name >defaultHtmlEscape</ param-name > < param-value >true</ param-value > </ context-param > < context-param > < param-name >contextConfigLocation</ param-name > < param-value >classpath*:META-INF/spring/applicationContext*.xml</ param-value > </ context-param > < listener > < listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class > </ listener > < filter > < filter-name >CharacterEncodingFilter</ filter-name > < filter-class >org.springframework.web.filter.CharacterEncodingFilter</ filter-class > < init-param > < param-name >encoding</ param-name > < param-value >UTF-8</ param-value > </ init-param > < init-param > < param-name >forceEncoding</ param-name > < param-value >true</ param-value > </ init-param > </ filter > < filter-mapping > < filter-name >CharacterEncodingFilter</ filter-name > < url-pattern >/*</ url-pattern > </ filter-mapping > < filter > < filter-name >HttpMethodFilter</ filter-name > < filter-class >org.springframework.web.filter.HiddenHttpMethodFilter</ filter-class > </ filter > < filter-mapping > < filter-name >HttpMethodFilter</ filter-name > < url-pattern >/*</ url-pattern > </ filter-mapping > < filter > < filter-name >springSecurityFilterChain</ filter-name > < filter-class >org.springframework.web.filter.DelegatingFilterProxy</ filter-class > </ filter > < filter-mapping > < filter-name >springSecurityFilterChain</ filter-name > < url-pattern >/*</ url-pattern > </ filter-mapping > < servlet > < servlet-name >studying-spring-security</ servlet-name > < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > < init-param > < param-name >contextConfigLocation</ param-name > < param-value >WEB-INF/spring/webmvc-config.xml</ param-value > </ init-param > < load-on-startup >1</ load-on-startup > </ servlet > < servlet-mapping > < servlet-name >studying-spring-security</ servlet-name > < url-pattern >/</ url-pattern > </ servlet-mapping > < session-config > < session-timeout >10</ session-timeout > < tracking-mode >COOKIE</ tracking-mode > </ session-config > </ web-app > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | log4j.rootLogger=error, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # Print the date in ISO 8601 format log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=application.log log4j.appender.R.MaxFileSize=100KB # Keep one backup file log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n |
データベース接続の設定
persistence.xml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?> < persistence version = "2.0" xmlns = "http://java.sun.com/xml/ns/persistence" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> < persistence-unit name = "persistenceUnit" transaction-type = "RESOURCE_LOCAL" > < provider >org.hibernate.ejb.HibernatePersistence</ provider > < properties > < property name = "hibernate.dialect" value = "org.hibernate.dialect.MySQLDialect" /> < property name = "hibernate.hbm2ddl.auto" value = "validate" /> < property name = "hibernate.ejb.naming_strategy" value = "org.hibernate.cfg.DefaultNamingStrategy" /> < property name = "hibernate.connection.charSet" value = "UTF-8" /> </ properties > </ persistence-unit > </ persistence > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?> < beans xmlns = "http://www.springframework.org/schema/beans" xmlns:context = "http://www.springframework.org/schema/context" xmlns:p = "http://www.springframework.org/schema/p" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> < bean id = "dataSource" class = "org.apache.commons.dbcp.BasicDataSource" destroy-method = "close" > < property name = "driverClassName" value = "com.mysql.jdbc.Driver" /> < property name = "url" value = "jdbc:mysql://localhost:3306/studying_spring_security" /> < property name = "username" value = "root" /> < property name = "password" value = "" /> < property name = "testOnBorrow" value = "true" /> < property name = "testOnReturn" value = "true" /> < property name = "testWhileIdle" value = "true" /> < property name = "timeBetweenEvictionRunsMillis" value = "1800000" /> < property name = "numTestsPerEvictionRun" value = "3" /> < property name = "minEvictableIdleTimeMillis" value = "1800000" /> < property name = "validationQuery" value = "SELECT 1" /> </ bean > < context:annotation-config /> < bean id = "entityManagerFactory" class = "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:persistenceUnitName = "persistenceUnit" p:dataSource-ref = "dataSource" /> </ beans > |
persistence.xmlファイルにデータベース接続設定を記述したいところなのですが
Spring Securityの標準の実装では、RememberMeトークンをデータベースに保存する場合、
JDBCを使用している(org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl)みたいで
DataSourceをSpringコンテナに登録しておく必要があるようです。
この部分もカスタマイズすればよいのですが、今回はパスで…
Entityクラスの作成
MyUser.java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | package com.mydomain.entity; import java.util.Collection; import javax.persistence.CollectionTable; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.MapKeyColumn; import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.JoinColumn; import org.springframework.security.core.CredentialsContainer; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @Entity @Table (name = "users" ) public class MyUser implements UserDetails, CredentialsContainer{ private static final long serialVersionUID = 1L; @Id private String username; private String password; private boolean enabled; private String contact; @ElementCollection (targetClass=MyAuthority. class , fetch=FetchType.EAGER) @CollectionTable ( name= "authorities" , joinColumns={ @JoinColumn (name= "username" , referencedColumnName= "username" )}) @MapKeyColumn (name= "authority" ) private Collection<GrantedAuthority> authorities; @Transient private boolean accountNonExpired = true ; @Transient private boolean accountNonLocked = true ; @Transient private boolean credentialsNonExpired = true ; @Override public void eraseCredentials() { password = null ; } @Override public boolean equals(Object rhs) { if (rhs instanceof User) { return username.equals(((User) rhs).username); } return false ; } @Override public int hashCode() { return username.hashCode(); } public String getContact() { return contact; } public void setContact(String contact) { this .contact = contact; } @Override public String getUsername() { return this .username; } public void setUsername(String username) { this .username = username; } @Override public String getPassword() { return this .password; } public void setPassword(String password) { this .password = password; } @Override public boolean isEnabled() { return this .enabled; } public void setEnabled( boolean enabled) { this .enabled = enabled; } @Override public boolean isAccountNonExpired() { return this .accountNonExpired; } public void setAccountNonExpired( boolean accountNonExpired) { this .accountNonExpired = accountNonExpired; } @Override public boolean isAccountNonLocked() { return this .accountNonLocked; } public void setAccountNonLocked( boolean accountNonLocked) { this .accountNonLocked = accountNonLocked; } @Override public boolean isCredentialsNonExpired() { return this .credentialsNonExpired; } public void setCredentialsNonExpired( boolean credentialsNonExpired) { this .credentialsNonExpired = credentialsNonExpired; } @Override public Collection<GrantedAuthority> getAuthorities() { return this .authorities; } public void setAuthorities(Collection<GrantedAuthority> authorities) { this .authorities = authorities; } } |
equals()メソッド、hashCode()メソッドは、User(org.springframework.security.core.userdetails)クラスを参考に実装しました。
CredentialsContainerインターフェイスの実装も同様に参考にしました。
…toString()メソッドはパスです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | package com.mydomain.entity; import javax.persistence.Embeddable; import org.springframework.security.core.GrantedAuthority; @Embeddable public class MyAuthority implements GrantedAuthority{ private static final long serialVersionUID = 1L; private String authority; @Override public String getAuthority() { return this .authority; } public void setAuthority(String authority) { this .authority = authority; } public boolean equals(Object obj) { if ( this == obj) { return true ; } if (obj instanceof MyAuthority) { return authority.equals(((MyAuthority) obj).authority); } return false ; } public int hashCode() { return this .authority.hashCode(); } public String toString() { return this .authority; } } |
equals()メソッド、hashCode()メソッド、toString()メソッドは、
SimpleGrantedAuthority(org.springframework.security.core.authority)クラスを参考に実装しました。
UserDetailsServiceクラスの作成
MyUserDetailsService.java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package com.mydomain.bizlogic; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.springframework.dao.DataAccessException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.mydomain.entity.MyUser; @Service public class MyUserDetailsService implements UserDetailsService { @PersistenceContext private EntityManager em; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { try { String jpql = "SELECT u FROM User u Where username = :username" ; Query query = this .em.createQuery(jpql, MyUser. class ); query.setParameter( "username" , username); MyUser user = (MyUser) query.getSingleResult(); return user; } catch (NoResultException exp) { throw new UsernameNotFoundException( "ユーザが見つかりません" ); } } } |
Spring Securityの設定
/login、/resourcesには、アクセス制限を設定せず、それ以外のURLにアクセス制限を設定します。
<authentication-provider>タグと<remember-me>タグのuser-service-ref属性に
作成したUserDetailsServiceインターフェイス実装クラスを指定します。
RememberMeトークンをデータベースに保存する場合、<remember-me>タグのdata-source-ref属性に
Springコンテナに登録されたDataSourceを指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <? xml version = "1.0" encoding = "UTF-8" ?> < beans:beans xmlns = "http://www.springframework.org/schema/security" xmlns:beans = "http://www.springframework.org/schema/beans" xmlns:p = "http://www.springframework.org/schema/p" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> < http auto-config = "true" use-expressions = "true" > < form-login login-processing-url = "/resources/j_spring_security_check" login-page = "/login" authentication-failure-url = "/login?login_error=t" default-target-url = "/" always-use-default-target = "true" /> < logout logout-url = "/resources/j_spring_security_logout" logout-success-url = "/" /> < intercept-url pattern = "/login*" access = "permitAll" /> < intercept-url pattern = "/resources/**" access = "permitAll" /> < intercept-url pattern = "/**" access = "hasRole('ROLE_USER')" /> < remember-me data-source-ref = "dataSource" user-service-ref = "myUserDetailsService" /> </ http > < authentication-manager alias = "authenticationManager" > < authentication-provider user-service-ref = "myUserDetailsService" > < password-encoder hash = "sha-256" /> </ authentication-provider > </ authentication-manager > < beans:bean id = "myUserDetailsService" class = "com.mydomain.bizlogic.MyUserDetailsService" /> </ beans:beans > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?> < beans xmlns = "http://www.springframework.org/schema/beans" xmlns:p = "http://www.springframework.org/schema/p" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> < bean id = "messageSource" class = "org.springframework.context.support.ReloadableResourceBundleMessageSource" p:basenames = "WEB-INF/i18n/messages" p:fallbackToSystemLocale = "false" p:fileEncodings = "UTF-8" p:defaultEncoding = "UTF-8" /> </ beans > |
SpringSecurity関連のクラスがSpringコンテナに登録される際に
ReloadableResourceBundleMessageSourceクラスなどからmessages_ja.propertiesファイルが読み込めないと
エラーメッセージが日本語化できないようです。
webmvc-config.xmlファイルが読み込まれる時点では、
SpringSecurity関連クラスのSpringコンテナへの登録が終わっているようなので
このファイルでReloadableResourceBundleMessageSourceクラスなどの設定をしていると
SpringSecurityのデフォルトのエラーメッセージを日本語で上書きされないみたいです。
1 | AbstractUserDetailsAuthenticationProvider.badCredentials=ログインID、パスワードが違います。 |
ReloadableResourceBundleMessageSourceクラスを使用するとnative2asciiで変換を行わなくてもよいようです。
Spring MVCの設定
webmvc-config.xml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?> < beans xmlns = "http://www.springframework.org/schema/beans" xmlns:mvc = "http://www.springframework.org/schema/mvc" xmlns:p = "http://www.springframework.org/schema/p" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> < mvc:annotation-driven /> < mvc:resources location = "/resources/" mapping = "/resources/**" /> < mvc:view-controller path = "/login" /> < mvc:view-controller path = "/" view-name = "index" /> < bean id = "internalResourceViewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver" p:viewClass = "org.springframework.web.servlet.view.JstlView" p:prefix = "/WEB-INF/views/" p:suffix = ".jspx" /> </ beans > |
Viewファイルの作成
login.jspx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | < html version = "2.0" xmlns:jsp = "http://java.sun.com/JSP/Page" xmlns:c = "http://java.sun.com/jsp/jstl/core" xmlns:fn = "http://java.sun.com/jsp/jstl/functions" xmlns:spring = "http://www.springframework.org/tags" xmlns:form = "http://www.springframework.org/tags/form" > < jsp:output doctype-root-element = "HTML" doctype-system = "about:legacy-compat" /> < jsp:directive.page contentType = "text/html;charset=UTF-8" pageEncoding = "UTF-8" /> < head > < meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" /> < c:url value = "/resources/style.css" var = "style" /> < link rel = "stylesheet" type = "text/css" href = "${style}" /> < title >ログイン</ title > </ head > < body > < div id = "page" > < h3 >ログイン</ h3 > < c:if test = "${not empty param.login_error}" > < div class = "errors" > < p >< c:out value = "${SPRING_SECURITY_LAST_EXCEPTION.message}" /></ p > </ div > </ c:if > < spring:url value = "/resources/j_spring_security_check" var = "form_url" /> < form name = "f" action = "${fn:escapeXml(form_url)}" method = "POST" > < table > < tbody > < tr > < th >< label for = "j_username" >ログインユーザ</ label ></ th > < td >< input id = "j_username" type = 'text' name = 'j_username' style = "width:98%" /></ td > </ tr > < tr > < th >< label for = "j_password" >パスワード</ label ></ th > < td >< input id = "j_password" type = 'password' name = 'j_password' style = "width:100px" /> < input id = "proceed" type = "submit" value = "ログイン" /></ td > </ tr > < tr > < td ></ td > < th > < input id = "_spring_security_remember_me" type = 'checkbox' name = '_spring_security_remember_me' value = "true" /> < label for = "_spring_security_remember_me" >ログインしたままにする</ label > </ th > </ tr > </ tbody > </ table > </ form > </ div > </ body > </ html > |
SpringSecurityのエラーメッセージはセッションに保存されているみたいなので <jsp:directive.page session="false" /> としているとエラーメッセージが表示されなくようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | < html version = "2.0" xmlns:jsp = "http://java.sun.com/JSP/Page" xmlns:c = "http://java.sun.com/jsp/jstl/core" xmlns:sec = "http://www.springframework.org/security/tags" > < jsp:output doctype-root-element = "HTML" doctype-system = "about:legacy-compat" /> < jsp:directive.page contentType = "text/html;charset=UTF-8" pageEncoding = "UTF-8" /> < head > < meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" /> < c:url value = "/resources/style.css" var = "style" /> < link rel = "stylesheet" type = "text/css" href = "${style}" /> < title >ようこそ</ title > </ head > < body > < div id = "page" > < h3 >ようこそ</ h3 > < p > < sec:authentication property = "principal.username" htmlEscape = "true" />さん< br /> あなたの連絡先は< sec:authentication property = "principal.contact" htmlEscape = "true" />です。< br /> < sec:authorize access = "hasRole('ROLE_ADMIN')" >※管理者権限が設定されています。</ sec:authorize > </ p > < c:url value = "/resources/j_spring_security_logout" var = "logout_url" /> < a href = "${logout_url}" >ログアウト</ a > </ div > </ body > </ html > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | body { margin : 0px ; padding : 0px ; font : 13px Arial , Helvetica , sans-serif ; color : #212121 ; } h 1 { margin-top : 0px ; font-size : 2.4em ; } p { margin-bottom : 1.8em ; line-height : 160% ; } table { margin : 0px auto ; } th, td { text-align : left ; } div.errors { background-color : #FFEBE8 ; border : solid 1px #DD3C10 ; width : 300px ; margin : 3px auto ; padding : 3px ; } #page { width : 900px ; margin : 0px auto ; padding : 30px 0px ; text-align : center ; } |
POMファイルの作成
pom.xml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | <? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?> < project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> < modelVersion >4.0.0</ modelVersion > < groupId >com.mydomain</ groupId > < artifactId >studying-spring-security-02</ artifactId > < packaging >war</ packaging > < version >1.0</ version > < name >studying-spring-security-02</ name > < properties > < java.version >1.7</ java.version > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > < spring.version >3.1.0.RELEASE</ spring.version > < spring-security.version >3.0.7.RELEASE</ spring-security.version > </ properties > < repositories > < repository > < id >spring-maven-release</ id > < name >Spring Maven Release Repository</ name > < url >http://maven.springframework.org/release</ url > </ repository > </ repositories > < pluginRepositories > < pluginRepository > < id >spring-maven-release</ id > < name >Spring Maven Release Repository</ name > < url >http://maven.springframework.org/release</ url > </ pluginRepository > < pluginRepository > < id >apache.snapshots</ id > < url >http://repository.apache.org/snapshots/</ url > </ pluginRepository > </ pluginRepositories > < dependencies > < dependency > < groupId >javax</ groupId > < artifactId >javaee-api</ artifactId > < version >6.0</ version > < scope >provided</ scope > </ dependency > < dependency > < groupId >javax.servlet</ groupId > < artifactId >jstl</ artifactId > < version >1.2</ version > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-context</ artifactId > < version >${spring.version}</ version > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-webmvc</ artifactId > < version >${spring.version}</ version > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-jdbc</ artifactId > < version >${spring.version}</ version > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-orm</ artifactId > < version >${spring.version}</ version > </ dependency > < dependency > < groupId >org.springframework.security</ groupId > < artifactId >spring-security-core</ artifactId > < version >${spring-security.version}</ version > </ dependency > < dependency > < groupId >org.springframework.security</ groupId > < artifactId >spring-security-config</ artifactId > < version >${spring-security.version}</ version > </ dependency > < dependency > < groupId >org.springframework.security</ groupId > < artifactId >spring-security-web</ artifactId > < version >${spring-security.version}</ version > </ dependency > < dependency > < groupId >org.springframework.security</ groupId > < artifactId >spring-security-taglibs</ artifactId > < version >${spring-security.version}</ version > </ dependency > < dependency > < groupId >org.hibernate</ groupId > < artifactId >hibernate-entitymanager</ artifactId > < version >3.6.10.Final</ version > </ dependency > < dependency > < groupId >commons-pool</ groupId > < artifactId >commons-pool</ artifactId > < version >1.5.6</ version > </ dependency > < dependency > < groupId >commons-dbcp</ groupId > < artifactId >commons-dbcp</ artifactId > < version >1.3</ version > </ dependency > < dependency > < groupId >mysql</ groupId > < artifactId >mysql-connector-java</ artifactId > < version >5.1.18</ version > </ dependency > < dependency > < groupId >junit</ groupId > < artifactId >junit</ artifactId > < version >4.10</ version > < scope >test</ scope > </ dependency > </ dependencies > < build > < finalName >studying-spring-security-02</ finalName > < plugins > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-compiler-plugin</ artifactId > < version >2.3.2</ version > < configuration > < source >${java.version}</ source > < target >${java.version}</ target > < encoding >${project.build.sourceEncoding}</ encoding > </ configuration > </ plugin > < plugin > < groupId >org.apache.tomcat.maven</ groupId > < artifactId >tomcat7-maven-plugin</ artifactId > < version >2.0-SNAPSHOT</ version > </ plugin > </ plugins > </ build > </ project > |
ビルドと実行
コマンドプロンプトを開きCドライブ直下の「studying-spring-security」フォルダに移動後、mvnコマンドを実行します。
cd c\studying-spring-security mvn clean package mvn tomcat7:run |
Webブラウザを開き「http://localhost:8080/studying-spring-security/」にアクセスします。
ログインユーザ/パスワードは admin/admin と user/user になります。
現時点での最新は「2.0-beta-1」だと思われるのですが、このVersionでtomcatを実行すると
「Unable to determine URL for WEB-INF/classes」的なエラー発生してしまいます。
これは、tomcat7-maven-pluginが使用しているtomcat(7.0.25)が原因とのことです。
エラーは出るもののとりあえずは動いてそうなので問題なさそうなのですが、
エラーが出ているのがなんとなく嫌な感じなのでSNAPSHOTにしてみました。
なにぶんSNAPSHOTなので日によって挙動が違うかもしれません…
おわりに
SpringSecurityは、もっとガチガチで入り込む余地があまりないような印象だったのですが
さわってみた感じ割と挟みどころがいろいろ用意されているようです。
全然使い込んではないのでなんとも言えませんが…
とりあえずSpringは期待できそうだ。!
Webの開発をJavaでとなるとSpringの今後に懸かってますね。!
…JavaでWebかぁ~
ないのかな?
- 参考URL
- http://news.mynavi.jp/articles/2010/03/25/spring3/003.html
- http://sites.google.com/site/soracane/home/springnitsuite/spring-security/spring-securityno-settei-houhou
- http://ameblo.jp/spring-beginner/entry-10239724907.html
- http://oajamfibia.wordpress.com/2011/07/05/writing-a-custom-jpa-userdetailservice/
- http://krams915.blogspot.jp/2010/12/spring-security-mvc-integration_18.html
- http://www.codercorp.com/blog/spring/security-spring/writing-custom-userdetailsservice-for-spring-security.html
- http://stackoverflow.com/questions/9580031/javax-naming-namenotfoundexception-resource-web-inf-classes-not-found-with-mav