Once you have these downloaded, i created a folder called AegisBornLibs which contains any libraries we are going to use. Extract the 2 zip files to this folder. Then you will want to run the installer for the MySQL driver. Next we want to open the AegisBornPhoton project and add the .dlls to the AegisBorn project. The files we want are FluentNHibernate.dll, NHibernate.ByteCode.Castle.dll, and Required_Bins\NHibernate.dll
Once these references are added to our project we are going to create our first entity classes - SfGuardUser, AegisBornCharacter, and AegisBornUserProfile. Again these are just like the SmartFoxServer model classes. We will be creating these classes in a folder called Models\Base. Before I create them, I go ahead and set up a server connection in the server explorer. Once my connection is established I create the Models\Base and Models\Map directories in my solution. From there I create the above 3 classes and my first map file:
public class SfGuardUser
{
public virtual int Id { get; set; }
public virtual string Username { get; set; }
public virtual string Password { get; set; }
public virtual string Salt { get; set; }
}
public class AegisBornUserProfile
{
public virtual int Id { get; set; }
public virtual SfGuardUser UserId { get; set; }
public virtual int CharacterSlots { get; set; }
}
public class AegisBornCharacter
{
public virtual int Id { get; set; }
public virtual SfGuardUser UserId { get; set; }
public virtual string Name { get; set; }
public virtual string Sex { get; set; }
public virtual string Class { get; set; }
public virtual int Level { get; set; }
public virtual int PositionX { get; set; }
public virtual int PositionY { get; set; }
}
public class SfGuardUserMap : ClassMap
{
public SfGuardUserMap()
{
Id(x => x.Id).Column("id");
Map(x => x.Username).Column("username");
Map(x => x.Password).Column("password");
Map(x => x.Salt).Column("salt");
Table("sf_guard_user");
}
}
public ISessionFactory SessionFactory { get; set; }
[Operation(OperationCode = (byte)OperationCode.Login)]
public OperationResponse OperationLogin(Peer peer, OperationRequest request)
{
var operation = new LoginSecurely(request);
if(!operation.IsValid)
{
return new OperationResponse(request, (int)ErrorCode.InvalidOperationParameter, operation.GetErrorMessage());
}
// Attempt to get user from db and check password.
try
{
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var user = session.CreateCriteria(typeof(SfGuardUser), "sf").Add(Restrictions.Eq("sf.Username", operation.UserName)).UniqueResult
var sha1 = SHA1CryptoServiceProvider.Create();
var hash = BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(user.Salt + operation.Password))).Replace("-", "");
transaction.Commit();
if (String.Equals(hash.Trim(), user.Password.Trim(), StringComparison.OrdinalIgnoreCase))
{
return operation.GetOperationResponse(0, "OK");
}
}
}
}
catch (Exception)
{
// Do nothing because we are about to throw them out anyway.
}
peer.PublishOperationResponse(new OperationResponse(request, (int)ErrorCode.InvalidUserPass, "The Username or Password is incorrect"));
peer.DisconnectByOtherPeer(this, request);
return null;
}
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(
MySQLConfiguration.Standard
.ConnectionString(cs => cs.Server("localhost")
.Database("cjrgam5_ab")
.Username("cjrgam5_ab")
.Password("user_ab1!")))
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf
.BuildSessionFactory();
}
The CreateSessionFactory function is only in this file while I test this code. Next post we will be extracting it into a helper class that will Lazy create the connection the first time we try to access the database. For more information on the configuration jump on over to http://wiki.fluentnhibernate.org/Database_configuration where you can see what each piece does. As for the Operation handler, we first make sure the operation is valid, meaning it has UserName and Password fields. After that we are following NHibernate's process for accessing the database, we create a session, then a transaction, then our query. Our query looks up the SfGuardUser by username and then rebuilds the password using the salt and our provided password and running it through an SHA1 digest. If the password isn't correct or there is no user, we throw errors.
The last changes we are going to make are to create a new error code called InvalidUserPass:
///
/// The username or password isn't correct, don't let them log in.
///
InvalidUserPass,
Now we have the catch and final returns to pass an InvalidUserPass error so the user doesn't know if they exist or not which will help with hacking attempts. We also kick them off the server, a handy feature.
So thats all this time. Next time we will make a helper class for NHibernate's session factory. Until then, enjoy!
No comments:
Post a Comment