Spring Securityの基礎入門 (Spring MVC版)

Springは非常に人気のあるJavaアプリケーション開発フレームワークです。Spring SecurityはSpringフレームワークに基づいており、Webアプリケーションのセキュリティを完全に解決するためのソリューションを提供します。Spring SecurityはSpring AOPとServletフィルタを使用します。その核心は一連のフィルタチェーンであり、これらのフィルタを通じてウェブリクエストレベルおよびメソッド呼び出しレベルでの認証と権限チェックが行われます。

Spring Securityの主な機能は2つあり、それはログイン認証と権限管理です。

入門編

まず、動作原理を理解するために、ユーザー名とパスワードがどこへ送られるのか、どのような認証が行われるのかを把握する必要があります。それにはまず通常の使い方を学ぶ必要があります。ここではデータベース認証を含めずに、認証マネージャーをXMLファイルで設定する簡単なデモを作ります。

1. pom.xmlに依存関係を追加する

Mavenプロジェクトを作成し、必要なディレクトリを準備した後、以下の依存関係を追加します。また、このプロジェクトは`tomcat7-maven-plugin`を使用して起動します。

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>sec-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <servletVersion>3.0</servletVersion>
        <springVersion>4.2.5.RELEASE</springVersion>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${springVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${springVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${springVersion}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.1.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.1.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <port>8080</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2. web.xmlの設定

フロントコントローラ、spring-\*.xmlファイルの読み込み、リスナー、Spring Securityのフィルタなどを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"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring*.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <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>
</web-app>

3. resourcesフォルダ内のspring-\*.xml設定

このデモではresourcesフォルダ内に2つのSpring関連の設定ファイルを配置します。1つはspring-mvc.xmlで、主にアノテーションスキャン、静的リソースマッピング、ビューリゾルバの設定を行います。もう1つは重要な`spring-security.xml`で、ログイン認証の設定を行います。

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"

       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.example"/>

    <mvc:annotation-driven></mvc:annotation-driven>

    <mvc:resources mapping="/static/css/**" location="/static/css/"></mvc:resources>
    <mvc:resources mapping="/static/js/**" location="/static/js/"></mvc:resources>
    <mvc:resources mapping="/static/img/**" location="/static/img/"></mvc:resources>
    <mvc:resources mapping="/static/fonts/**" location="/static/fonts/"></mvc:resources>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

spring-security.xml

<?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: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 pattern="/favicon.ico" security="none"/>
    <http pattern="/static/**" security="none"/>
    <http pattern="/auth/login" security="none"/>
    <http pattern="/login-failed.html" security="none"/>

    <http use-expressions="false">
        <intercept-url pattern="/**" access="ROLE_USER" />
        <form-login login-page="/auth/login"  default-target-url="/home"
                    always-use-default-target="true" authentication-failure-url="/login-failed"/>
        <csrf disabled="true"/>
    </http>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="admin" password="123456" authorities="ROLE_USER"/>
                <user name="root" password="root" authorities="ROLE_USER"/>
            </user-service>
        </authentication-provider>
    </authentication-manager>
</beans:beans>

ページのインターセプトルール中の`form-login`タグの設定について説明します:

<form-login login-page="/auth/login"  default-target-url="/home" always-use-default-target="true"  authentication-failure-url="/login-failed"/>
<!--
	login-page : ログインページのURL
	default-target-url :認証成功後のリダイレクト先
	authentication-failure-url :認証失敗後のリダイレクト先 
-->
<csrf disabled="true"/>

4. コントローラー層にマッピングを追加する

IndexControllerクラスを作成し、ログイン成功後のホーム画面へのマッピング`/home`、ログインページへのマッピング`/auth/login`、そしてログイン失敗時のページへのマッピング`/login-failed`を追加します。これらは全てJSPページを返すため、webappフォルダ内にviewsフォルダを作成し、`home.jsp`、`login.jsp`、`login_failed.jsp`を作成します。

@Controller
public class MainController {

    @RequestMapping("/home")
    public String showHome(){
        System.out.println("ホーム表示");
        return "home" ;
    }

    @RequestMapping("/auth/login")
    public String showLogin(){
        System.out.println("ログインページ表示");
        return "login" ;
    }

    @RequestMapping("/login-failed")
    public String showFailedLogin(){
        System.out.println("ログイン失敗ページ表示");
        return "login_failed" ;
    }
}

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
    <title>ログインページ </title>
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="/static/css/style.min.css" rel="stylesheet">

</head>

<body>
<div class="row lyear-wrapper">
    <div class="lyear-login">
        <div class="login-center">
            <div class="login-header text-center">
                <a href="index.html"> <img alt="light year admin" src="/static/img/logo-sidebar.png"> </a>
            </div>
            <form action="/login" method="POST">
                <div class="form-group has-feedback feedback-left">
                    <input type="text" placeholder="ユーザー名を入力してください" class="form-control" name="username" />
                    <span class="mdi mdi-account form-control-feedback" aria-hidden="true"></span>
                </div>
                <div class="form-group has-feedback feedback-left">
                    <input type="password" placeholder="パスワードを入力してください" class="form-control" name="password" />
                    <span class="mdi mdi-lock form-control-feedback" aria-hidden="true"></span>
                </div>

                <div class="form-group">
                    <button class="btn btn-block btn-primary" type="submit" >ログイン</button>
                </div>
            </form>
            <hr>
        </div>
    </div>
</div>
<script type="text/javascript" src="/static/js/jquery.min.js"></script>
<script type="text/javascript" src="/static/js/bootstrap.min.js"></script>

</body>
</html>

注意すべき点:

  • 2つの入力フィールドは`name="username"`と`name="password"`であるべきです。Spring Securityはデフォルトでこれらのパラメータを受け取りますが、必要に応じて`spring-security.xml`の`form-login`タグで`username-parameter`と`password-parameter`を変更できます。
  • Spring Securityはデフォルトで`/login`へのフォーム送信を処理します。そのため、コントローラーでログインページのパスを`/login`に設定すると、そのパスを除外する必要があります。このデモでは`/auth/login`に設定しています。

5. webappフォルダに静的リソースを追加する

webappフォルダ内にstaticフォルダを作成し、その中に`img`、`js`、`fonts`、`css`フォルダを配置します。これは必須ではありませんが、見た目を整えるために推奨されます。

6. 動作確認

`tomcat7-maven-plugin`の設定により、ポート8080でアクセスできます。`http://localhost:8080/auth/login`にアクセスすると、`spring-security.xml`に設定された2つのユーザー`admin`と`root`(パスワードはそれぞれ`123456`と`root`)のみがログインできます。

タグ: SpringSecurity SpringMVC Maven Tomcat

8月6日 21:53 投稿