Java Springの逆引きメモ -10ページ目

Java Springの逆引きメモ

JavaのSpring frameworkのメモを書いていきます!
初心者の勉強ノートなので間違いがあるかもしれませんが、何かヒントになることがあれば幸いです。

SpringSecurityでは、taglibが用意されています。

それを利用すると、ログインユーザが持っているロールによってリンクを制御できます!


早速サンプルを見てみましょう。



【サンプルJSP】


<%@ page language="java" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"% >
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags " %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="css/default.css" type="text/css" />

<title>トップページ</title>
</head>
<body>
<a href="logout">ログアウト</a>
<br />

<sec:authorize ifAnyGranted="ROLE_ADMIN">
<a href="editUser.do">管理者のみがリンク表示されます</a><br />
</sec:authorize>



</body>
</html>




【説明】

ロールのチェックをするには、authorize タグを使用します。

ロールの判定の仕方は、ifAllGranted、 ifAnyGranted、 ifNotGrantedの3種類があります。

カンマ区切りでロールを指定します。


ifAllGranted ・・・ログインユーザが指定のロールすべてを持っている場合

ifAnyGranted ・・・ログインユーザが指定のロールのうちどれかを持っている場合

ifNotGranted ・・・ログインユーザが指定のロールを持っていない場合



このタグを使用するだけでリンクや文字列などの表示を制御できます。


便利でしょ?




【補足】

WEBだと良く出る要望が、

「閲覧権限のない画面へのリンクは表示しないでほしい」

だと思います。

上記のサンプルのように権限でリンク表示を制御する場合、この要望を満たすにはリンク1つずつについて必要なロールをすべて記述する必要があります。

これは記述が大変な上に、ロールが増えるたびにすべて書き直さないといけません。


そうすると、パスを指定して、ログインユーザがそのパスの認可が通るかどうかを判定する機構が必要になります。


これは結構きついです。。

なかなか便利なtaglibですが、どうも上記のことはできないようです。


一応、別の記事でこの実現方法を見てみようと思っています。(以下の参考を参照)




参考:

・閲覧許可がある画面のリンクのみ表示するには?

・実際に認証と認可をWEBにつけるには? (基本編:設定方法)

SpringSecurityでラクラクセキュリティ対策






前回までに、SpringSecurityの設定方法や動きを見てきました。

ここでは、認証がされて無事にログインした後に、JSP上でログイン情報を表示する方法を見てみます。



JSP以外の設定は、以前の記事 を参照してみてください。



【JSPファイル】

<%@ page language="java" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"% >
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags " %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="css/default.css" type="text/css" />

<title>トップページ</title>
</head>
<body>
<a href="logout">ログアウト</a>
<br />
ログインユーザ:<sec:authentication property="principal.username" />



</body>
</html>



【説明】

SpringSecurityではtaglibが用意されています。

これを使用すると、取得が面倒な情報も簡単に取得できます!


まず、taglibの宣言を見てみましょう。

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags " %>


ここで定義されているtaglibはいくつかあります。

一応、記述してみましょうか。


 ・authentication ・・・Authentication オブジェクトのgetterを呼び出します。

            上記のログインユーザで記述しているprincipal.username は以下のような意味です。

              authentication.getPrincipal().getUserName()

            クラスは、ログイン情報を持っています。ユーザID、パスワード、有効性、ロールなどです。


 ・authorize ・・・ログインユーザが指定したロールを持っていた場合にタグの内部が表示されます。

           ロールの判定の仕方は、ifAllGranted、 ifAnyGranted、 ifNotGrantedの3種類があります。



上記を使用すれば、ログインユーザのIDを表示したり、

ログインユーザがもっているロールに応じてリンクを表示したり非表示にしたりできます。

どうです?

簡単でしょ?




参考:

・実際に認証と認可をWEBにつけるには? (基本編:設定方法)

・ロールによって画面のリンクの表示/非表示を制御するには?

・閲覧許可がある画面のリンクのみ表示するには?

SpringSecurityでラクラクセキュリティ対策




前回 は、設定ファイル上にログインユーザのIDとPWを記述して認証する方法をみてみました!


今回はいよいよDBからログインID・PWを取得して認証します。

これも設定だけでできますニコニコ

では早速みてみましょう!


以下のsecurityApplication.xmlファイル以外は前回の設定と同じなので、前回の記事を参照してくださいませー。



【設定ファイル(securityApplication.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:util="http://www.springframework.org/schema/util"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:sec="http://www.springframework.org/schema/security"
 xsi:schemaLocation="
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/util
  http://www.springframework.org/schema/util/spring-util.xsd
  http://www.springframework.org/schema/security
  http://www.springframework.org/schema/security/spring-security-2.0.1.xsd
">

  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.postgresql.Driver"/>
    <property name="url">
      <value>jdbc:postgresql://localhost/test?useUnicode=true&amp;characterEncoding=utf-8</value>
    </property>
    <property name="username" value="user" />
    <property name="password" value="pass" />
 </bean>

 <!-- 認証と認可の設定です --> 
 <sec:http auto-config="true" access-denied-page="/403.jsp" >
  <!-- 認可のURL設定 -->
  <sec:intercept-url pattern="/secure/sys*" access="ROLE_ADMIN"/> 
  <sec:intercept-url pattern="/secure/usr*" access="ROLE_ADMIN,ROLE_USER"/>
  <sec:intercept-url pattern="/secure/**" access="IS_AUTHENTICATED_FULLY"/>
  <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
  <!-- 認証の設定 -->
  <sec:form-login login-page="/login.jsp" default-target-url="/top.jsp" authentication-failure-url="/error.jsp"/> 
  <sec:logout logout-url="/logout"  logout-success-url="/login.jsp" invalidate-session="true"/>
  <sec:anonymous granted-authority="ROLE_ANONYMOUS"/>
 </sec:http>
   
   
 <!-- 
  ログインユーザの情報の設定。SQL文を指定してDBから取得する方法もあります。 
 -->
 <sec:authentication-provider>
  <sec:jdbc-user-service data-source-ref="dataSource" 
  users-by-username-query="
    SELECT login_id, login_pw, 'true'
      FROM user
     WHERE login_id = ?"
     
  authorities-by-username-query="
    SELECT login_id, role 
      FROM user 
     WHERE login_id = ?" /> 
</sec:authentication-provider> 
 

</beans>




【説明】

前回の記事と違いを見てください。


<beanタグ>

まず、dataSourceのbeanがあります。

これはDBと接続するためです。

ここではサンプルを単純にするため、securityApplicationと同じファイルに記述しています。

実際の開発では、他でもdataSourceは使用するので他のファイルに記述しましょう!

<httpタグ>
次に、httpタグですが、これは前回の記事と同じです。


authentication-providerタグ>

最後に、本命登場!

authentication-providerの中身のタグが前回と違ってますね!

属性にSQLが記述されていますが、それぞれ、パスワードの認証のためのSQLと

権限のロールを取得するためのSQLです。


それぞれプレースホルダを持っています。

そこには、ログインIDが置換されます。


select文の抽出の順番は決まっているので注意です。

パスワードの認証のためのSQLは、「ユーザID」、「パスワード」、「ユーザの有効性」。

「ユーザの有効性」はログインアカウントを論理削除している場合に使用します。

ここでは論理削除のフィールドがないものとして'true'に設定しています。

ここの値は、"0"か"1"、もしくは、"true"か"false"です。

もうひとつ、

認可のSQL文は、「ユーザID」、「権限」。


たったのこれだけです!

簡単だし、分かりやすいですよね?


ぜひぜひ使って楽をしましょう(^^)




参考:

・SpringSecurityの機能について

・実際に認証と認可をWEBにつけるには? (基本編:設定方法)

http://itpro.nikkeibp.co.jp/article/COLUMN/20090224/325394/?ST=develop&P=7



前回は、テーブルのフィールド名とオブジェクトのgetter名が違う場合のサンプルを見ました。

 ・DBにデータを登録するには?


ここでは、フィールド名とgetter名が同じ場合で、簡単にできる例を見てみましょう。



【サンプル】

 private SimpleJdbcInsert insertMember;
 final private static String UPDATE_MEMBER_SQL
    = "update t_member set kana=:kana, kanji=:kanji where id=:id";
  
 
 @Override
 protected void initDao() {
    //
    this.insertMember =
    new SimpleJdbcInsert(getDataSource())
    .withTableName("t_member");
    //.usingGeneratedKeyColumns("id");
    this.namedParameterTemplate = new NamedParameterJdbcTemplate(getDataSource());
    this.simpleTemplate = new SimpleJdbcTemplate(getDataSource());
 }
   
 
 @Override
 public int insertMember(Member member) {
  //
  SqlParameterSource paramSource = new BeanPropertySqlParameterSource(member);
  int num = this.insertMember.execute(paramSource);
  //
  return num;
 }
 
 
 @Override
 public int updateMember(Member member) {
  //
  SqlParameterSource paramSource = new BeanPropertySqlParameterSource(member);
  int num = this.namedParameterTemplate.update(UPDATE_MEMBER_SQL, paramSource);
  //
  return num;
 }




【説明】

BeanPropertySqlParameterSource

前回のサンプルと違って、マッピング用のクラス(UpdateMemberParameter )がなくなっているのが分かるでしょうか?

そうです。実装の必要がなくなるんです。

変わりに、BeanPropertySqlParameterSourceを使用します。

このクラスは、コンストラクタで指定されたオブジェクトのgetter名をキーにしたパラメタクラスを作成します。

やることは、これだけです!


SimpleJdbcInsert

さらにinsertの場合だけは自動でSQL文まで記述してくれます。

それを行っているのがSimpleJdbcInsert クラスです。

このクラスは、initDao()内でnewして、初期化をします。

(SpringのHPのサンプルでは、setDataSource()内で初期化をしていましたが)

このとき、withTableNameでテーブル名を指定します。

さらに他の設定があれば、以下のように連続で指定できます。

withTableName().usingGeneratedKeyColumns("id"); 


あとは、実際に実行するときにexucuteメソッドを呼び出すだけです!


<その他のSimpleJdbcInsert のメソッド>

さらにここでは使用していませんが、executeAndReturnKeyというメソッドも存在します。

これを使うとprimaryキーの値を自動で生成した上に、生成した値を返してくれます。

(準備として、SimpleJdbcInsertのusingGeneratedKeyColumnsを呼び出す必要があります)

かなり簡単になりますよね。



【デメリット】

ここで言うとMemberクラスのsetter/getterの名称をリファクタリングするとなると

Daoの記述をすべて直すか、テーブルのフィールド名をすべて変更しないといけません。


また、逆のパターンでテーブルのフィールド名を変更する場合、SQL文だけでなく、Memberクラスのgetter/setterの名称を変更する必要があります。


ですので、将来変更する可能性がある箇所にはこの方法は使用しないほうが良いでしょう。

前回のやり方の方が変更点が少なくてよいかと思います。



うまく使えばかなり楽になると思うので、うまく使っていきましょうラブラブ




参考:

・DBにデータを登録するには?

・DBからデータを取得するには?(SimpleJdbcTemplate のサンプル)

・DBからデータを取得するには?(NamedParameterJdbcTemplateのサンプル)








ここでは、SpringJDBCを使用してDBに値をinsert/updateする例を見てみます。

ケースによっていろいろな方法があるのですが、その一部を記述します。


例によって、Dao部分のみ記述します。



【insert/updateのサンプル (フィールド名とMemberのgetter名が違う場合)】

public class MemberDaoImpl extends WakJdbcDaoSupport implements MemberDao {
  protected NamedParameterJdbcTemplate namedParameterTemplate;
  protected SimpleJdbcTemplate simpleTemplate;
 
  protected void initDao()
  {
    this.namedParameterTemplate = new NamedParameterJdbcTemplate(getDataSource());
    this.simpleTemplate = new SimpleJdbcTemplate(getDataSource());
  }

  //会員更新SQL文 
  final private static String UPDATE_MEMBER_SQL = "update t_member set f_kana=:kana, f_kanji=:kanji "
     + " where f_id=:key_id";
  final private static String INSERT_MEMBER_SQL = "insert into t_member(f_id, f_kana, f_kanji) "
     + " values(:id, :kana, :kanji)";

  //会員更新マッピング
  protected class UpdateMemberParameter extends MapSqlParameterSource 
  {
    public UpdateMemberParameter(Member member) {
      addValue("key_id", member.getId());
      addValue("id", member.getId());
      addValue("kanji", member.getKanji());
      addValue("kana", member.getKana());
    }

  }


 @Override
 /** 会員情報をinsertします。登録数を返します */
 public int insertMember(Member member) {
  //
  SqlParameterSource paramSource = new UpdateMemberParameter(member);
  int num = this.namedParameterTemplate.update(INSERT_MEMBER_SQL, paramSource);
  //
  return num;
 }
 
 
 @Override
 /** 会員情報をupdateします。更新数を返します */
 public int updateMember(Member member) {
  //
  SqlParameterSource paramSource = new UpdateMemberParameter(member);
  int num = this.namedParameterTemplate.update(UPDATE_MEMBER_SQL, paramSource);
  //
  return num;
 }
}





【説明】

実は、DBのテーブルのフィールド名とデータオブジェクトのgetter名が同じ場合はもっと簡単な方法もあります。

同じではないケースの方が多いと思いますので、ここでは、それぞれの名称が違うケースを書きました。


<SQL文の記述>
まず、SQL文を記述していますが、名前つきプレースホルダを使用しています。

そうです!

以前記事にしましたNamedParameterJdbcTemplateを使用するためです。


<マッピング>

では、SQL文に記述したプレースホルダのパラメタ名とデータのマッピングはどこでやっているのでしょう。

UpdateMemberParameter クラスで実装しています。

コンストラクタ内でaddValue()を呼び出していますが、これはMapSqlParameterSource クラスが持っているメソッドで、パラメタ名と値を結びつけるメソッドです。

ちなみに、このクラスは update/insert文の両方で使用できるので、再利用できる利点があります。


addValueで"key_id"というテーブルのフィールド名と関係ない値を設定しています。

これは、updateのwhere句で使用する値とsetで更新する値とを分けるための工夫です。

ここでは意味がありませんが、あるidのレコードを探して、

見つけたレコードのidの値を変更したい場合などに役に立ちます。



<SQLの実行>

SQL文の実行は単純です。

namedParameterTemplateのupdateを呼び出すだけです。

引数は、SQL文とマッピングした値を持ったMapSqlParameterSource です。


割と簡単でしょ?


でも、ひとつひとつのクラスの役割が明確なので、とっても見通しが良いのです!



<補足>

SpringSecurityには、他にも様々な機能があります。

ここでは触れませんが、名前だけ紹介しておきます。


・自動でidを生成してinsertしてくれる機能(executeAndReturnKeyメソッド:生成したidは返却してくれる)

・insert文を書かずにinsertしてくれる機能(SimpleJdbcInsert クラス)

・オブジェクトのgetter名をマップのキーにしてパラメタクラスを作る機能(BeanPropertySqlParameterSourceクラス)

・Listに入ったオブジェクトを一回のメソッドで繰り返しSQL文を実行する機能(batchUpdateメソッド)



また、SimpleJdbcTemplate クラスを使用して"?"のプレースホルダでDBを更新(insert/update)することもできます。

ぜひぜひいろいろ使って安全性と楽を手に入れてくださいニコニコ



参考:

・DBへのデータ登録を簡単にするには?  (SimpleJdbcInsert, BeanPropertySqlParameterSourceのサンプル)

・SpringJDBCで作成したDaoとビジネスロジックを連携するには?

・DBからデータを取得するには?(SimpleJdbcTemplate のサンプル)

・DBからデータを取得するには?(NamedParameterJdbcTemplateのサンプル)

http://static.springframework.org/spring/docs/2.5.x/reference/jdbc.html