C# + MongoDBでログイン認証

 ASP.NET MVC + MongoDB環境でこのブログを作っている。今回はパスワード認証あたりが平文だったので、データベース直いじりで登録済みのパスワードをSHA256ハッシュにして、認証ロジックをそれに対応させた。

参考:http://dobon.net/vb/dotnet/string/md5.html

 パスワードにさらにユーザー名を付加し、それをなにかしらの文字列を使ってハッシュ化する。下記のようなメソッドを用意した。
private static string GetSHA256 (string userName, string pw)

{
//HMAC-SHA1を計算する文字列
var s = $"{userName}@{pw}";
//キーとする文字列
var key = "somestring";

//文字列をバイト型配列に変換する
byte[] data = System.Text.Encoding.UTF8.GetBytes(s);
byte[] keyData = System.Text.Encoding.UTF8.GetBytes(key);

byte[] bs;
//HMACSHA256オブジェクトの作成
using (var hmac = new HMACSHA256(keyData))
{
//ハッシュ値を計算
bs = hmac.ComputeHash(data);
}

//byte型配列を16進数に変換
var result = BitConverter.ToString(bs).ToLower().Replace("-", "");

return result;
}


 ハッシュ値を得るメソッドは用意したので、MongoDBに保存してあるユーザー情報と照会する。
public static bool Login(string id, string pw, IResponseCookies cookies)

{
var userCollection = DbConnection.db.GetCollection<BsonDocument>("user");
var filter = Builders<BsonDocument>.Filter.Eq("_id", id);
var doc = userCollection.Find<BsonDocument>(filter).FirstOrDefault<BsonDocument>();
if (doc == null)
{
return false;
}
else
{
var sha256 = GetSHA256(doc.GetValue("_id").AsString, pw);
if (sha256 != doc.GetValue("pw").AsString)
{
return false;
}
else
{
// 認証処理が続く
comment: 0

MongoDB: セッションのトークンを管理してもらう

 MongoDBには、期限切れとなったドキュメントを自動で削除してくれる機能がある。このブログではDBにMongoDBを使っており、期限切れのセッショントークンはこの機能を利用して削除している。

 sessionというコレクションにトークンデータを保存する。保存されるドキュメントのデータとしてトークン文字列token、作成日時createdAtがあるとする。このコレクションにドキュメントが保存された場合に、一定時間後にドキュメントを削除したい。下記のようにインデックスを作る。
db.session.createIndex( { "createdAt": 1 }, { expireAfterSeconds: XXX } )

 これでXXX秒後にコレクションsession内のドキュメントは自動で削除される。ただし期限が切れて直ちに消えるわけではない。バックグラウンドタスクが60秒ごとに走っているので、このタスクの対象になったタイミングで処理される。

https://docs.mongodb.com/manual/core/index-ttl/
comment: 0

C#, MongoDB: MapReduceで集計処理2

 前回とりあえずメモがてら、このブログで行ってるMapReduce処理を載せた。さらに引き続きMapReduce処理をもうちょい学んでみた。
https://absurd.azurewebsites.net/Article/5

 前回はMapReduce処理結果を表示するために取ってきていた。MapReduce処理実行時のオプションとして、結果を取ってくる以外にそのままDBへ保存することもできる。
 ただ保存には注意が必要なように思う。
1.Replace
 コレクション内すべてのドキュメントを消し、MapReduce処理結果を保存
2.Merge
 Update命令と同様。同IDのドキュメントがなければInsertされる
3.Reduce
 同IDのドキュメントの置換
4.Inline
 結果をクライアントへ返す

 たぶん汎用性が高いのはMergeあたりか。今回はMapReduce結果それぞれにコレクションを用意したのでReplaceを使ったけど。
 下記がこのブログのサイドバーのタグ集計を行っているMapReduce処理。
public static void MapReduceTag()

{
var collection = DbConnection.db.GetCollection<BsonDocument>("entry");
var map = (BsonJavaScript)@"
function() {
emit('tag', this.tag);
}";

var reduce = (BsonJavaScript)@"
function(key, values) {
var result = {};

values.forEach(function(value){
value.forEach(function(v){
if (!(v in result)) {
result[v] = 1;
} else {
result[v] += 1;
}
});
});

return result;
}";

var options = new MapReduceOptions<BsonDocument, object>();
var filter = Builders<BsonDocument>.Filter.Eq("showFlg", true);
options.Filter = filter;
options.OutputOptions = MapReduceOutputOptions.Replace("tagInfo");

collection.MapReduce(map, reduce, options);

}

comment: 0

このブログの技術的要素

 先月に.NET Coreの正式版リリースが迫っているという報を聞いて、このブログをぼちぼちと作り始めて形になってきた。ブログを作るというのは既存のサービス上で開設するのではなく、できあいのブログエンジンを使うでもなく、正式リリースがせまっていた.NET Coreを使って作った。

 自作なので自分で必要なものを選んでいった。ちなみに自分の使いたいと思っていたサービスを使いつつ、月額費用がタダになるように選んでいった。
 まずAzure。もうクラウドが話題になって久しい。クラウドサービスはAWSが圧倒的なシェアを持ちつつもAzureがそれを追うという状態。そして大企業がリソースをローカルからクラウドへ移すという事例をメールマガジンでよく読むようになってきた。そんな中で仕事でクラウドを触る機会はなく、このままいっさいクラウドに触れないというのはまずいかなと思った。なのでクラウドサービスを使いたいと考えていた。あとはVPSでDocker上でコンテナとしてWebアプリを動かそうと考えていたが、そうなるとタダとはいかなくなるので別の機会にやることに。とりあえず本ブログはAzure WebAppServiceの無料枠で。
 続いてデータベースはmlabというMongoDBのホスティングサービスを使った。Azureで金を払ってデータベースを用意するのもいいが、MongoDBを使いたいと思っていたところ、軽い使い方(使用可能領域がぼちぼちのサイズでリソースが共用だったり)ならタダだったのでホスティングサービスmlabを利用。サーバのリージョンを選べるが、タダだと日本のサーバは選べない。なのでタダの米国西部を選択。これに合わせてAzureのほうのサーバも米国西部にした。
 画像などの容量の多いファイルのサーブについて。クラウドだと回線でデータを送受信した分も金をとられる。そしてmlabでタダの範囲内に容量を収めることを考えると、画像ファイルは敵である。そこでそれらのファイルはOneDriveに入れることにした。最初はMongoDBにGridFSという仕組みがあるのでそっちを使おうとしたけど。OneDriveについては通常のOneDriveサービス画面でファイルをアップして、埋め込みリンクを取得してという手順で今は使っている。ここらはAPIがあるので近々管理者ページでうまく連携できるようにしたい。
 ASP.NET MVC周りについて。現状は.NET Coreでも、.NET Frameworkベースで動作するものを使っている。MongoDBのドライバがまだ.NET Core対応のものが出ていないので。対応版が近々リリースされるので、それが出たら純粋な?.NET Coreに切り替える。

 このブログのベースにある技術的なところをとりあえず大まかに並べて書いていった。続いてブログを作るためにどんなC#コードを書いたかを記事にしていきたい。
comment: 0

MongoDB, C#: MapReduceで集計処理

 MongoDBにもドキュメントの集計を行う機能がある。それがMapReduce。
Gihyo MongoDBでの集計処理

 このブログのサイドバーに、タグごとにそれがついた記事が何件あるかを集計してある。この集計にMapReduceを使っている。
 タグは一件の記事ごとにArrayに入れてある。集計では公開記事のそのArrayを全件とってきて、中のタグをカウントしている。というわけでそのコード。

var collection = DbConnection.db.GetCollection<BsonDocument>("entry");

var map = (BsonJavaScript)@"
function() {
emit('tag', this.tag);
}";

var reduce = (BsonJavaScript)@"
function(key, values) {
var result = {};

values.forEach(function(value){
value.forEach(function(v){
if (!(v in result)) {
result[v] = 1;
} else {
result[v] += 1;
}
});
});

return result;
}";

var filter = Builders<BsonDocument>.Filter.Eq("showFlg", true);
var options = new MapReduceOptions<BsonDocument, Dictionary<string, object>>();
options.Filter = filter;

var results = collection.MapReduce(map, reduce, options);
var result = results.First();
var json = result.Values.Last().ToJson();
var dict = (Dictionary<string, int>)BsonSerializer.Deserialize(json, typeof(Dictionary<string, int>));


 MongoDBからDriverが受け取ったBSONから、どうすれば直接集計結果のKeyValueペアを抜き出せるかわからなかった。なので必要な部分だけJSON文字列で抜き取って、それをデシリアライズして辞書型にした。
comment: 0