Apache Shiro Quickstart その３

前回はApache Derbyを使いました。でも以下のような流儀は古いので、MongoDBでユーザー情報を管理したいと思います。
http://qiita.com/namikitakeo/items/e711d7374f645f667ac6

    ij> CREATE TABLE USERS (ID varchar(255) PRIMARY KEY NOT NULL, PASS varchar(255) NOT NULL);
    ij> CREATE TABLE ROLES (ID varchar(255) PRIMARY KEY NOT NULL, ROLE varchar(255) NOT NULL);
    ij> INSERT INTO USERS (ID,PASS) VALUES ('root','password');
    ij> INSERT INTO ROLES (ID,ROLE) VALUES ('root','admin');

MongoDBサービスを起動します。

    $ sudo su -
    # /usr/bin/mongod --logpath /var/log/mongodb/mongod.log --rest

REST APIを試してみます。テーブル定義も不要だし、JSONをPOSTするだけでユーザー情報を管理できます。

    $ curl http://localhost:28017/shiro/users/
    $ curl -d '{id:"root", pass:"secret", roles:["user","admin"]}' http://localhost:28017/shiro/users/
    $ curl -d '{id:"guest", pass:"guest", roles:["guest"]}' http://localhost:28017/shiro/users/
    $ curl http://localhost:28017/shiro/users/

ユーザー情報データベースを検索します。SQLではありませんが、コマンドラインからもユーザー情報を管理できます。

    $ mongo
    > show dbs;
    > use shiro;
    > show collections;
    > db.users.find();
    > exit;

ここらへんを参考にユーザー情報をデータベースから取得するようにします。オリジナルからかなり修正しています。
https://github.com/TensorWrench/shiro-mongodb-realm

```java:MongoUserPasswordRealm.java
package com.tensorwrench.shiro.realm;

import java.util.List;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.*;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.mongodb.*;

/**
 *  Does authentication and authorization from a MongoDB.
 *  Expects the documents to have a several fields:
 *  <ul>
 *  <li> passwordAuthentication - object with authentication info
 *  <ul>
 *     <li>name - user name
 *     <li>password - password hash
 *  </ul>
 *  <li>roles - an array of roles
 *  <ul>
 */
public class MongoUserPasswordRealm extends AuthorizingRealm {
	protected DBCollection collection;
	
	public MongoUserPasswordRealm() {
		MongoClient mongo = new MongoClient("localhost",27017);
		DB db = mongo.getDB("shiro");
		collection = db.getCollection("users");
	}
	
	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof UsernamePasswordToken;
	}
	
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
		if(!(authToken instanceof UsernamePasswordToken)) {
			throw new AuthenticationException("This realm only supports UsernamePasswordTokens");
		}
		UsernamePasswordToken token=(UsernamePasswordToken) authToken;

		if(token.getUsername() == null) {
			throw new AuthenticationException("Cannot log in null user");
		}
		
		return findPasswordForUsername(token.getUsername());
	}
		
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
		DBObject obj= collection.findOne(new BasicDBObject("id",principals.getPrimaryPrincipal().toString()));
		if(obj != null) {
			for(Object r: (List<Object>) obj.get("roles")) {
				info.addRole(r.toString());
			}
		}
		
		return info;
	}
	
	/**
	 * Does the actual mechanics of creating the Authentication info object from the database.
	 */
	public AuthenticationInfo findPasswordForUsername(String username) {
		DBObject obj= collection.findOne(new BasicDBObject("id",username));
		
		if(obj == null) {
			throw new UnknownAccountException("Unkown user " + username);
		}
		
		String password=(String)obj.get("pass");
		return new SimpleAuthenticationInfo(username, password, getName());
	}
}
```

webディレクトリに移動。

    $ cd shiro-root-1.3.2/samples/web

以下のようにshiro.iniを修正します。

    defaultRealm = com.tensorwrench.shiro.realm.MongoUserPasswordRealm

    #jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
    #jdbcRealm.authenticationQuery = select pass from users where id = ?
    #jdbcRealm.userRolesQuery = select role from roles where id = ?

    #ds=com.jolbox.bonecp.BoneCPDataSource
    #ds.driverClass=org.apache.derby.jdbc.ClientDriver
    #ds.jdbcUrl=jdbc:derby://localhost:1527/test
    #jdbcRealm.dataSource=$ds

以下のようにpom.xmlに依存関係を追加します。

    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver</artifactId>
        <version>3.5.0</version>
    </dependency>

Jettyを実行。

    $ mvn jetty:run

WEBブラウザで以下のURLを参照してください。
http://localhost:9080/