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