データベースを使用したSpring Securityフォームのログイン
このチュートリアルでは、Springセキュリティで(XMLと注釈の両方を使用して)データベース認証を実行する方法を説明します。
使用される技術:
-
Spring 3.2.8.RELEASE
-
春のセキュリティ3.2.3.RELEASE
-
Spring JDBC 3.2.3.RELEASE
-
Eclipse 4.2
-
JDK 1.6
-
Maven 3
-
Tomcat 6または7(Servlet 3.x)
-
MySQLサーバ5.6
以前のリンク://spring-security/spring-security-form-login-example/[ログインフォームのメモリ内認証]は再利用され、次の機能をサポートします:
-
JDBC-JDBCとMySQLを使用したデータベース認証.
-
Spring Security、JSP TagLib、
`sec:authorize access =” hasRole( ‘ROLE__USER’) `
。 403アクセス拒否ページをカスタマイズします。
1.プロジェクトデモ
2.プロジェクトディレクトリ
最終的なプロジェクト構造(XMLベース)を確認する:
最終的なプロジェクト構造を見直す(注釈ベース):
3.プロジェクトの依存関係
Spring、Spring Security、JDBC、Taglib、MySQLの依存関係を取得する
pom.xml
<properties> <jdk.version>1.6</jdk.version> <spring.version>3.2.8.RELEASE</spring.version> <spring.security.version>3.2.3.RELEASE</spring.security.version> <jstl.version>1.2</jstl.version> <mysql.connector.version>5.1.30</mysql.connector.version> </properties> <dependencies> <!-- Spring 3 dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</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> <!-- Spring Security --> <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-config</artifactId> <version>${spring.security.version}</version> </dependency> <!-- Spring Security JSP Taglib --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${spring.security.version}</version> </dependency> <!-- jstl for jsp page --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <!-- connect to mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.connector.version}</version> </dependency> </dependencies> </project>
4.データベース
データベース認証を実行するには、ユーザーとロールの詳細を格納するテーブルを作成する必要があります。このhttp://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/reference/htmlsingle/#user-schema[Spring Securityユーザースキーマリファレンス]を参照してください。
users`と
user__roles`テーブルを作成するためのMySQLスクリプトです。
4.1「ユーザー」テーブルを作成します。
users.sql
CREATE TABLE users ( username VARCHAR(45) NOT NULL , password VARCHAR(45) NOT NULL , enabled TINYINT NOT NULL DEFAULT 1 , PRIMARY KEY (username));
4.2 “user__roles”テーブルを作成します。
user__roles.sql
CREATE TABLE user__roles ( user__role__id int(11) NOT NULL AUTO__INCREMENT, username varchar(45) NOT NULL, role varchar(45) NOT NULL, PRIMARY KEY (user__role__id), UNIQUE KEY uni__username__role (role,username), KEY fk__username__idx (username), CONSTRAINT fk__username FOREIGN KEY (username) REFERENCES users (username));
4.3テストのためにいくつかのレコードを挿入します。
INSERT INTO users(username,password,enabled) VALUES ('mkyong','123456', true); INSERT INTO users(username,password,enabled) VALUES ('alex','123456', true); INSERT INTO user__roles (username, role) VALUES ('mkyong', 'ROLE__USER'); INSERT INTO user__roles (username, role) VALUES ('mkyong', 'ROLE__ADMIN'); INSERT INTO user__roles (username, role) VALUES ('alex', 'ROLE__USER');
5.春のセキュリティ設定
XMLとアノテーションの両方でのSpringセキュリティ。
5.1 MySQLに接続するためのDataSourceを作成します。
spring-database.xml
<beans xmlns="http://www.springframework.org/schema/beans" 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.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> </beans>
Springアノテーションに相当する:
SecurityConfig.java
package com.mkyong.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @EnableWebMvc @Configuration @ComponentScan({ "com.mkyong.web.** " }) @Import({ SecurityConfig.class }) public class AppConfig { @Bean(name = "dataSource") public DriverManagerDataSource dataSource() { DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(); driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver"); driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/test"); driverManagerDataSource.setUsername("root"); driverManagerDataSource.setPassword("password"); return driverManagerDataSource; } @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/pages/"); viewResolver.setSuffix(".jsp"); return viewResolver; } }
5.2 `jdbc-user-service`を使ってデータベース認証を行うためのクエリを定義します。
spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" 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.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd"> <!-- enable use-expressions --> <http auto-config="true" use-expressions="true"> <intercept-url pattern="/admin** ** " access="hasRole('ROLE__ADMIN')"/> <!-- access denied page --> <access-denied-handler error-page="/403"/> <form-login login-page="/login" default-target-url="/welcome" authentication-failure-url="/login?error" username-parameter="username" password-parameter="password"/> <logout logout-success-url="/login?logout" /> <!-- enable csrf protection --> <csrf/> </http> <!-- Select users and user__roles from database --> <authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query= "select username,password, enabled from users where username=?" authorities-by-username-query= "select username, role from user__roles where username =? "/> </authentication-provider> </authentication-manager> </beans:beans>
Spring Securityアノテーションに相当する:
SecurityConfig.java
package com.mkyong.config; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired DataSource dataSource; @Autowired public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource) .usersByUsernameQuery( "select username,password, enabled from users where username=?") .authoritiesByUsernameQuery( "select username, role from user__roles where username=?"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/** ** ").access("hasRole('ROLE__ADMIN')") .and() .formLogin().loginPage("/login").failureUrl("/login?error") .usernameParameter("username").passwordParameter("password") .and() .logout().logoutSuccessUrl("/login?logout") .and() .exceptionHandling().accessDeniedPage("/403") .and() .csrf(); } }
6. JSPページ
カスタムログインページ用のJSPページ。
6.1デフォルトのページで、 ”
ROLE__USER
“権限を持つユーザにコンテンツを表示するための、Spring Security JSP taglib `sec:authorize`の使用方法を示します。
hello.jsp
<%@taglib prefix="sec" uri="http://www.springframework.org/security/tags"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <html> <body> <h1>Title : ${title}</h1> <h1>Message : ${message}</h1> <sec:authorize access="hasRole('ROLE__USER')"> <!-- For login user --> <c:url value="/j__spring__security__logout" var="logoutUrl"/> <form action="${logoutUrl}" method="post" id="logoutForm"> <input type="hidden" name="${__csrf.parameterName}" value="${__csrf.token}"/> </form> <script> function formSubmit() { document.getElementById("logoutForm").submit(); } </script> <c:if test="${pageContext.request.userPrincipal.name != null}"> <h2> User : ${pageContext.request.userPrincipal.name} | <a href="javascript:formSubmit()"> Logout</a> </h2> </c:if> </sec:authorize> </body> </html>
6.2カスタムログインフォームを表示するページ。
login.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@page session="true"%> <html> <head> <title>Login Page</title> <style> .error { padding: 15px; margin-bottom: 20px; border: 1px solid transparent; border-radius: 4px; color: #a94442; background-color: #f2dede; border-color: #ebccd1; } .msg { padding: 15px; margin-bottom: 20px; border: 1px solid transparent; border-radius: 4px; color: #31708f; background-color: #d9edf7; border-color: #bce8f1; } #login-box { width: 300px; padding: 20px; margin: 100px auto; background: #fff; -webkit-border-radius: 2px; -moz-border-radius: 2px; border: 1px solid #000; } </style> </head> <body onload='document.loginForm.username.focus();'> <h1>Spring Security Login Form (Database Authentication)</h1> <div id="login-box"> <h2>Login with Username and Password</h2> <c:if test="${not empty error}"> <div class="error">${error}</div> </c:if> <c:if test="${not empty msg}"> <div class="msg">${msg}</div> </c:if> <form name='loginForm' action="<c:url value='/j__spring__security__check'/>" method='POST'> <table> <tr> <td>User:</td> <td><input type='text' name='username'></td> </tr> <tr> <td>Password:</td> <td><input type='password' name='password'/></td> </tr> <tr> <td colspan='2'><input name="submit" type="submit" value="submit"/></td> </tr> </table> <input type="hidden" name="${__csrf.parameterName}" value="${__csrf.token}"/> </form> </div> </body> </html>
6.3このページはパスワードで保護されており、認証されたユーザー ”
ROLE__ADMIN
“のみがアクセスできます。
admin.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@page session="true"%> <html> <body> <h1>Title : ${title}</h1> <h1>Message : ${message}</h1> <c:url value="/j__spring__security__logout" var="logoutUrl"/> <form action="${logoutUrl}" method="post" id="logoutForm"> <input type="hidden" name="${__csrf.parameterName}" value="${__csrf.token}"/> </form> <script> function formSubmit() { document.getElementById("logoutForm").submit(); } </script> <c:if test="${pageContext.request.userPrincipal.name != null}"> <h2> Welcome : ${pageContext.request.userPrincipal.name} | <a href="javascript:formSubmit()"> Logout</a> </h2> </c:if> </body> </html>
6.4カスタム403アクセス拒否ページ。
403.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <html> <body> <h1>HTTP Status 403 - Access is denied</h1> <c:choose> <c:when test="${empty username}"> <h2>You do not have permission to access this page!</h2> </c:when> <c:otherwise> <h2>Username : ${username} <br/> You do not have permission to access this page!</h2> </c:otherwise> </c:choose> </body> </html>
7. Spring MVCコントローラ
シンプルなコントローラ。
MainController.java
package com.mkyong.web.controller; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; @Controller public class MainController { @RequestMapping(value = { "/", "/welcome** ** " }, method = RequestMethod.GET) public ModelAndView defaultPage() { ModelAndView model = new ModelAndView(); model.addObject("title", "Spring Security Login Form - Database Authentication"); model.addObject("message", "This is default page!"); model.setViewName("hello"); return model; } @RequestMapping(value = "/admin** ** ", method = RequestMethod.GET) public ModelAndView adminPage() { ModelAndView model = new ModelAndView(); model.addObject("title", "Spring Security Login Form - Database Authentication"); model.addObject("message", "This page is for ROLE__ADMIN only!"); model.setViewName("admin"); return model; } @RequestMapping(value = "/login", method = RequestMethod.GET) public ModelAndView login(@RequestParam(value = "error", required = false) String error, @RequestParam(value = "logout", required = false) String logout) { ModelAndView model = new ModelAndView(); if (error != null) { model.addObject("error", "Invalid username and password!"); } if (logout != null) { model.addObject("msg", "You've been logged out successfully."); } model.setViewName("login"); return model; } //for 403 access denied page @RequestMapping(value = "/403", method = RequestMethod.GET) public ModelAndView accesssDenied() { ModelAndView model = new ModelAndView(); //check if user is login Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (!(auth instanceof AnonymousAuthenticationToken)) { UserDetails userDetail = (UserDetails) auth.getPrincipal(); model.addObject("username", userDetail.getUsername()); } model.setViewName("403"); return model; } }
8.デモ
8.1。デフォルトページXML –
http://localhost:8080/spring-security-loginform-database/
注釈 –
http://localhost:8080/spring-security-loginform-database-annotation/
8.2 `/admin`ページにアクセスしようとすると、” mkyong ”
ROLE__ADMIN
だけがアクセスできます。
8.3。 “alex”が `/admin`にアクセスしようとすると、403 access deniedページが表示されます。
デフォルトページの8.3 “alex”は、 `sec:authorize`の使用方法を示しています。
8.4。 “mkyong”が `/admin`にアクセスしようとすると、管理ページが表示されます。
ソースコードをダウンロードする
XML形式のダウンロード – リンク://wp-content/uploads/2011/08/spring-security-login-form-database-xml.zip[spring-security-login-form-database-xml.zip](16 KB)
注釈バージョンをダウンロードする – リンク://wp-content/uploads/2011/08/spring-security-login-form-database-annotation.zip[spring-security-login-form-database-annotation.zip](22 KB)
参考文献
セキュリティリファレンス – jdbc-ser-service +]。
http://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/reference/htmlsingle/#user-schema
[Spring
セキュリティリファレンス – juser-schema]。
http://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/reference/htmlsingle/#taglibs
[Spring
セキュリティリファレンス – taglibs]。リンク://spring-security/spring-security-hello-world-annotation-example/[Spring
セキュリティHello Worldの注釈の例]。
http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/guides/form.html
[Creating
カスタムログインフォーム]。リンク://spring-security/customize-http-403-access-denied-page-in-spring-security/[Spring
セキュリティ – 403アクセス拒否ページをカスタマイズする方法]