Java
MongoDB
Shiro

Apache Shiro Quickstart その3

More than 1 year has passed since last update.

前回は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

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/