組み込みのWCF/c#コンポーネントを使用せずに、
- クライアントをRESTfulサービスに認証する
- クライアントでのAPI呼び出しでの認証の失敗を処理する
これは教育的な演習です。認証には組み込みのメソッドがあることに気付きました。これを最初から実行して、すべてがどのように機能するかを理解したいと思います。
パスワードのハッシュとチェックのロジックと、パスワードを検証する公開されたREST呼び出しがありますが、そこから続行する方法がわかりません。
バックグラウンド
Restサービスの認証方法の作成に苦労しています。
これまでのところ、パスワードのハッシュを作成し、ソルトを作成して保存し、ユーザーを認証することができました。ただし、すべてのwcf REST要求をカプセル化して、要求された場合(GET、POST)にログインを要求し、ログインしない場合はログインしないようにする方法がわかりません。
私は自分の認証技術を使用していて、WebサービスとC#を初めて使用するため、どこから始めればよいのか本当にわかりません。
だから私はこれへのアプローチを提供できる人に300人の担当者を提供するつもりです。
コード
これは私の残りのサービスです:
[ServiceContract(Namespace = "http://tempuri.org")]
[XmlSerializerFormat]
public interface IService
{
.... all of my GET, POST, PUT and DELETE requests
{
[DataContract(Name="Student")]
[Serializable]
public class Student
{
[DataMember(Name = "StudentID")]
public string StudentID { get; set; }
[DataMember(Name = "FirstName")]
public string FirstName { get; set; }
[DataMember(Name = "LastName")]
public string LastName { get; set; }
[DataMember(Name = "Password")]
public string Password;
[DataMember(Name = "Salt")]
public byte[] Salt;
//note the use of public datamembers for password and salt, not sure how to implement private for this.
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
[Serializable]
public class Service: IService
{
#region Authentication, hash and salt
protected RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
public byte[] GenerateSalt() //Generate random salt for each password
{
byte[] salt = new byte[10000];
random.GetNonZeroBytes(salt);
return salt;
}
public static byte[] Hash(string value, byte[] salt) //hash and salt the password
{
return Hash(Encoding.UTF8.GetBytes(value), salt);
}
public static byte[] Hash(byte[] value, byte[] salt) // create hash of password
{
byte[] saltedValue = value.Concat(salt).ToArray();
return new SHA256Managed().ComputeHash(saltedValue); //initialise new isntance of the crypto class using SHA-256/32-byte (256 bits) words
}
public string AuthenticateUser(string studentID, string password) //Authentication should always be done server side
{
var result = students.FirstOrDefault(n => n.StudentID == studentID);
//find the StudentID that matches the string studentID
if (result != null)
//if result matches then do this
{
byte[] passwordHash = Hash(password, result.Salt);
string HashedPassword = Convert.ToBase64String(passwordHash);
//hash salt the string password
if (HashedPassword == result.Password)
//check if the HashedPassword (string password) matches the stored student.Password
{
return result.StudentID;
// if it does return the Students ID
}
}
return "Login Failed";
//if it doesnt return login failed
}
#endregion
コンソールアプリからもホストしていますが、web.configファイルやapp.configファイルがありません。また、独自の認証方法を使用したため、基本認証が機能するかどうかはわかりません。
また、サービスSOAとステートレスを維持するためにセッションを維持したくありません。
コンソールアプリ:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.Transport;
host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Host opened");
Console.ReadLine();
}
}
}
クライアント側では、認証のために非常に基本的なことをしていることに注意してください。
private void Login_Click(object sender, RoutedEventArgs e)
{
//Authenticate user (GET Request)
string uri = string.Format("http://localhost:8000/Service/AuthenticateUser/{0}/{1}", textBox1.Text, passwordBox1.Password);
XDocument xDoc = XDocument.Load(uri);
string UserAuthenticationID = xDoc.Element("string").Value;
Int32 value;
if (Int32.TryParse(UserAuthenticationID, out value))
{
MainWindow authenticatedidentification = new MainWindow();
authenticatedidentification.SetLabel(UserAuthenticationID);
authenticatedidentification.Show();
this.Close();
}
else
{
label1.Content = UserAuthenticationID;
}
}
したがって、メインアプリがこれらの残りのリクエストにアクセスするために、上記のいずれかがあれば、メインアプリケーションに他に何を実行する必要があるかわかりません。