Login/Sign up and authentication process - Asp.net Web API, C#, Android Application, SQL server

Implement Login/Sign up and authentication process to demonstrate my skills and understanding using technologies like ASP.NET C#, WebApi, Java and SQL server

Tools

  • Microsoft Visual Studio 2017 or latest
  • Android Studio
  • SQL server 2017
  • No-IP desktop application

Additional Information and plugin

  • To register For NO-IP service Here
  • For the tutorial on NO-IP and forwarding rule, click Here
  • To download and install UNITY.WEBAPI for repository pattern and dependency injection in ASP.NET WebApi click Here

Creating projects, solution and database

Android studio

Step 1


Step 2


Step 3


Visual Studio 2017

Step 1: Create a new project



Step 2: Install Unity.WebAPI

Open "Package manager console " and paste the following command


PM> Install-Package Unity.WebAPI -Version 5.3.0

SQL server

Step 1: Create a database

Right click on database folder in SQL server from the context menu select New Database


Step 2: Login 

Right click on login under Security/Login. From the context menu select new login and save


Sign Up process




When the user will click on the signup button. The application will make an API call to check for email address uniqueness, save the user credentials and return a status code 200 with the JWT (Json Web Token) also

namespace AndroidApi.Controllers.Api
{
[AllowAnonymous]
[RoutePrefix("v1/account")]
public class AccountController : ApiController
{
private readonly IAccountRepository _repository;
public AccountController(IAccountRepository repository)
{
_repository = repository;
}
[Route("signup")]
public IHttpActionResult Signup(AccountViewModel item)
{
try
{
AccountViewModel result = new AccountViewModel();
if (item == null)
return BadRequest("No user info");
if (_repository.IsEmailUnique(item.Email))
result = _repository.Save(item);
else
return Conflict(); //409
return Ok(result);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
}
}
namespace AndroidApi.Models.ViewModel
{
public class AccountViewModel : StatusCodeViewModel
{
[JsonProperty("userid")]
public int UserId { get; set; }
[JsonProperty("user")]
public string User { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
[JsonProperty("isactive")]
public bool IsActive { get; set; }
}
}
namespace AndroidApi.Models.Repository
{
public class AccountRepository : IAccountRepository
{
private static string connectionString;
public AccountRepository()
{
if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["appctxt"]))
connectionString = ConfigurationManager.AppSettings["appctxt"];
}
public bool IsEmailUnique(string email)
{
bool result = true;
DataSet dsResult = new DataSet();
string[] tableNames = new string[] { "CustomerAccessKey" };
SqlParameter[] sqlParameters = new SqlParameter[]
{
new SqlParameter("@email", email)
};
SqlHelper.FillDataset(connectionString, CommandType.StoredProcedure, "UserGetByEmail", dsResult, tableNames, sqlParameters);
if (dsResult.Tables.Count > 0 && dsResult.Tables[0].Rows.Count > 0)
{
result = false;
}
return result;
}
public AccountViewModel Save(AccountViewModel item)
{
AccountViewModel result = new AccountViewModel();
result = Save(item.UserId, item);
return result;
}
public AccountViewModel Save(int id, AccountViewModel item)
{
AccountViewModel result = null;
DataSet dsResult = new DataSet();
string[] tableNames = new string[] { "CustomerAccessKey" };
SqlParameter[] sqlParameters = new SqlParameter[]
{
new SqlParameter("@userId", item.UserId),
new SqlParameter("@username", item.User),
new SqlParameter("@email", item.Email),
new SqlParameter("@password", item.Password),
};
SqlHelper.FillDataset(connectionString, CommandType.StoredProcedure, "UserSave", dsResult, tableNames, sqlParameters);
if (dsResult.Tables.Count > 0 && dsResult.Tables[0].Rows.Count > 0)
{
result = SqlHelper.ToType<AccountViewModel>(dsResult.Tables[0].Rows[0]);
result.StatusCode = 200;
result.Message = "saved";
}
return result;
}
}
}
namespace AndroidApi.Models.Interface
{
public interface IAccountRepository
{
AccountViewModel Save(AccountViewModel item);
AccountViewModel Save(int id, AccountViewModel item);
AccountViewModel GetByEmailAndPassword(AccountViewModel item);
AccountViewModel GetByUserId(int userId);
bool IsEmailUnique(string email);
}
}
public class SignUp extends AsyncTask<String, String, String> {
ProgressDialog progressDialog;
HttpURLConnection connection = null;
BufferedReader reader = null;
Activity activity;
public SignUp(Activity activity) {
this.activity = activity;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// display a progress dialog for good user experiance
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Please Wait");
progressDialog.setCancelable(false);
progressDialog.show();
}
@Override
protected String doInBackground(String... params) {
String result = null;
AccountViewModel account;
Gson gson;
try {
URL url = new URL(params[0]);
String email = params[2];
String password = params[3];
String username = params[1];
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.connect();
JSONObject jsonObject = new JSONObject();
jsonObject.put("email", email);
jsonObject.put("password", password);
jsonObject.put("user", username);
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes(jsonObject.toString());
wr.flush();
wr.close();
int statusCode = connection.getResponseCode();
if(statusCode == 200){
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line ="";
while ((line = reader.readLine()) != null){
buffer.append(line);
}
String jsonObjectHome = buffer.toString();
result = jsonObjectHome;
}
if (statusCode == 400){
account = new AccountViewModel();
account.setStatusCode(statusCode);
account.setMessage("bad request");
gson = new Gson();
result = gson.toJson(account);
}
if (statusCode == 404){
account = new AccountViewModel();
account.setStatusCode(statusCode);
account.setMessage("User not found please sign up");
gson = new Gson();
result = gson.toJson(account);
}
if (statusCode == 500){
account = new AccountViewModel();
account.setStatusCode(statusCode);
account.setMessage("Internal server error");
gson = new Gson();
result = gson.toJson(account);
}
if (statusCode == 409){
account = new AccountViewModel();
account.setStatusCode(statusCode);
account.setMessage("Email already exists");
gson = new Gson();
result = gson.toJson(account);
}
} catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
} finally {
if(connection != null) {
connection.disconnect();
}
try {
if(reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.cancel();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_signup, container, false);
try{
InitializeControl(view);
signUp = view.findViewById(R.id.BtnSignUp);
signUp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (IsValid()){
AccountViewModel account = SignUp(getActivity());
if (account.getStatusCode() == 200){
TokenViewModel token = GetToken(getActivity(), account);
if (token.getStatusCode() == 200){
SaveTokenSession(token);
NavigateToMainActivity();
}else{
Toast messageBox = Toast.makeText(getActivity() , token.getMessage() , Toast.LENGTH_LONG);
messageBox.show();
}
}else {
Toast messageBox = Toast.makeText(getActivity() , account.getMessage() , Toast.LENGTH_LONG);
messageBox.show();
}
}
}
});
}
catch (Exception ex){
String t = ex.getMessage();
}
return view;
}
public class AccountViewModel extends StatusCodeViewModel {
private int UserId;
private String Username;
private String Email;
private String Password;
private boolean IsActive;
public int getUserId() {
return UserId;
}
public void setUserId(int userId) {
UserId = userId;
}
public String getUsername() {
return Username;
}
public void setUsername(String username) {
Username = username;
}
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
public String getPassword() {
return Password;
}
public void setPassword(String password) {
Password = password;
}
public boolean isActive() {
return IsActive;
}
public void setActive(boolean active) {
IsActive = active;
}
}


Login Process






@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().setTitle("Login");
View view = inflater.inflate(R.layout.fragment_login, container, false);
try{
InitializeModel(view);
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(IsControlValid()){
AccountViewModel account = GetUserDetails(getActivity());
if (account.getStatusCode() == 200){
TokenViewModel token = GetToken(getActivity(), account);
if (token.getStatusCode() == 200){
SaveTokenSession(token);
NavigateToMainActivity();
}else{
Toast messageBox = Toast.makeText(getActivity() , token.getMessage() , Toast.LENGTH_LONG);
messageBox.show();
}
}else{
Toast messageBox = Toast.makeText(getActivity() , account.getMessage() , Toast.LENGTH_LONG);
messageBox.show();
}
}
}
});
}catch (Exception ex){
String v = ex.getMessage();
}
return view;
}
namespace AndroidApi.Models.Repository
{
public class AccountRepository : IAccountRepository
{
private static string connectionString;
public AccountRepository()
{
if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["appctxt"]))
connectionString = ConfigurationManager.AppSettings["appctxt"];
}
public AccountViewModel GetByEmailAndPassword(AccountViewModel item)
{
AccountViewModel result = null;
DataSet dsResult = new DataSet();
string[] tableNames = new string[] { "CustomerAccessKey" };
SqlParameter[] sqlParameters = new SqlParameter[]
{
new SqlParameter("@email", item.Email),
new SqlParameter("@password", item.Password),
};
SqlHelper.FillDataset(connectionString, CommandType.StoredProcedure, "UserGetByEmailAndPassword", dsResult, tableNames, sqlParameters);
if (dsResult.Tables.Count > 0 && dsResult.Tables[0].Rows.Count > 0)
{
result = SqlHelper.ToType<AccountViewModel>(dsResult.Tables[0].Rows[0]);
result.StatusCode = 200;
result.Message = "OK";
}
return result;
}
}
}
namespace AndroidApi.Controllers.Api
{
[AllowAnonymous]
[RoutePrefix("v1/account")]
public class AccountController : ApiController
{
private readonly IAccountRepository _repository;
public AccountController(IAccountRepository repository)
{
_repository = repository;
}
[HttpPost]
[Route("login")]
public IHttpActionResult Login([FromBody] AccountViewModel item)
{
try
{
if (item == null)
return BadRequest("No user info");
AccountViewModel result = _repository.GetByEmailAndPassword(item);
if (result == null)
return NotFound();
return Ok(result);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
}
}
public class Login extends AsyncTask<String, String, String> {
ProgressDialog progressDialog;
HttpURLConnection connection = null;
BufferedReader reader = null;
Activity activity;
public Login(Activity activity) {
this.activity = activity;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// display a progress dialog for good user experiance
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Please Wait");
progressDialog.setCancelable(false);
progressDialog.show();
}
@Override
protected String doInBackground(String... params) {
String result = null;
AccountViewModel account;
Gson gson;
try {
URL url = new URL(params[0]);
String email = params[1];
String password = params[2];
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.connect();
JSONObject jsonObject = new JSONObject();
jsonObject.put("email", email);
jsonObject.put("password", password);
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes(jsonObject.toString());
wr.flush();
wr.close();
int statusCode = connection.getResponseCode();
if(statusCode == 200){
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line ="";
while ((line = reader.readLine()) != null){
buffer.append(line);
}
String jsonObjectHome = buffer.toString();
result = jsonObjectHome;
}
if (statusCode == 400){
account = new AccountViewModel();
account.setStatusCode(statusCode);
account.setMessage("bad request");
gson = new Gson();
result = gson.toJson(account);
}
if (statusCode == 404){
account = new AccountViewModel();
account.setStatusCode(statusCode);
account.setMessage("User not found please sign up");
gson = new Gson();
result = gson.toJson(account);
}
if (statusCode == 500){
account = new AccountViewModel();
account.setStatusCode(statusCode);
account.setMessage("Internal server error");
gson = new Gson();
result = gson.toJson(account);
}
} catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
} finally {
if(connection != null) {
connection.disconnect();
}
try {
if(reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.cancel();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
try{
if (isNetworkConnected(AccountActivity.this, getBaseContext())){
NavigateToLogin();
}else {
NavigateToNoInternet();
Toast messageBox = Toast.makeText(AccountActivity.this , "No internet ..." , Toast.LENGTH_LONG);
messageBox.show();
}
}catch (Exception ex){
Log.e("Error", ex.getMessage());
}
}
private void NavigateToLogin() {
LoginFragment fragment = new LoginFragment();
android.support.v4.app.FragmentTransaction fmTransaction = getSupportFragmentManager().beginTransaction();
fmTransaction.replace(R.id.MainFrameLayout, fragment);
fmTransaction.commit();
}


Validate Token


namespace AndroidApi.Models.Repository
{
public class TokenRepository : ITokenRepository
{
private static string connectionString = string.Empty;
private static string tokenKey = string.Empty;
private readonly IAccountRepository _repository;
public TokenRepository()
{
_repository = new AccountRepository();
if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["appctxt"]))
connectionString = ConfigurationManager.AppSettings["appctxt"];
if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["tokenPrivateKey"]))
tokenKey = ConfigurationManager.AppSettings["tokenPrivateKey"];
}
public TokenViewModel GenerateToken(AccountViewModel item)
{
TokenViewModel result = new TokenViewModel();
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenKey));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var header = new JwtHeader(credentials);
var payload = new JwtPayload
{
{ "cus", item.UserId},
{ "timestamp", DateTime.Now},
};
var secToken = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
result.Token = handler.WriteToken(secToken);
result.StatusCode = 200;
result.Message = "OK";
return result;
}
public AccountViewModel ValidToken(string token)
{
AccountViewModel result = new AccountViewModel();
int userId = 0;
string timeStamp = string.Empty;
var handler = new JwtSecurityTokenHandler();
var tokenS = handler.ReadToken(token) as JwtSecurityToken;
foreach (var items in tokenS.Claims)
{
if (items.Type == "cus")
int.TryParse(items.Value, out userId);
if (items.Type == "timestamp")
timeStamp = items.Value;
}
if (IsTimeValid(timeStamp))
{
result = _repository.GetByUserId(userId);
}
return result;
}
private bool IsTimeValid(string timeStamp)
{
if (string.IsNullOrEmpty(timeStamp))
{
return false;
}
DateTime oDate = Convert.ToDateTime(timeStamp.Replace("\"", string.Empty));
if (oDate < DateTime.Today)
{
return false;
}
return true;
}
}
}
namespace AndroidApi.Controllers.Api
{
[RoutePrefix("v1/access")]
public class TokenController : ApiController
{
private readonly ITokenRepository _repository;
public TokenController(ITokenRepository repository)
{
_repository = repository;
}
[HttpPost]
[Route("token")]
public IHttpActionResult GetToken(AccountViewModel item)
{
try
{
TokenViewModel result = new TokenViewModel();
if (item == null || item.UserId == 0)
return BadRequest("No user info");
result = _repository.GenerateToken(item);
if (string.IsNullOrEmpty(result.Token) || result == null)
return InternalServerError();
return Ok(result);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
[HttpGet]
[Route("validtoken")]
public IHttpActionResult ValidToken()
{
try
{
HttpContext httpContext = HttpContext.Current;
string authToken = httpContext.Request.Headers["Authorization"];
AccountViewModel result = new AccountViewModel();
if (string.IsNullOrEmpty(authToken))
return BadRequest();
result = _repository.ValidToken(authToken);
if (result.StatusCode == 200)
return Ok(result);
else
return NotFound();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
}
}
token = GetTokenFromSession();
if (token == null){
Logout();
NavigateToAccountActivity();
}
else {
String userDetailsJson = GetUserDetailsFromToken(token.getToken(), MainActivity.this);
AccountViewModel userDetails = DeserializeUserDetails(userDetailsJson);
if (userDetails.getStatusCode() == 200){
}
else {
Toast messageBox = Toast.makeText(MainActivity.this , userDetails.getMessage() , Toast.LENGTH_LONG);
messageBox.show();
Logout();
NavigateToAccountActivity();
}
}
private AccountViewModel DeserializeUserDetails(String userDetailsJson) {
AccountViewModel result = new AccountViewModel();
JSONObject jsonResult = null;
try {
jsonResult = new JSONObject(userDetailsJson);
result.setStatusCode(jsonResult.getInt("StatusCode"));
result.setMessage(jsonResult.getString("Message"));
if (result.getStatusCode() == 200) {
result.setUserId(jsonResult.getInt("userid"));
result.setUsername(jsonResult.getString("user"));
result.setEmail(jsonResult.getString("email"));
result.setPassword(jsonResult.getString("password"));
result.setActive(jsonResult.getBoolean("isactive"));
}
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
private String GetUserDetailsFromToken(String token, MainActivity activity) {
String result = null;
try {
result = new ValidToken(activity).execute(config.getValidTokenEndPoint(), token).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return result;
}
private void NavigateToAccountActivity() {
Intent main = new Intent(MainActivity.this, AccountActivity.class);
startActivity(main);
}
private void Logout() {
sharedpreferences = getSharedPreferences(AccountActivity.tokenSession, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.clear();
editor.commit();
}
private TokenViewModel GetTokenFromSession() {
TokenViewModel result = new TokenViewModel();
sharedpreferences = getSharedPreferences(AccountActivity.tokenSession, Context.MODE_PRIVATE);
result.setToken(sharedpreferences.getString(AccountActivity.tokenKey.toString(), ""));
if (result.getToken() == "")
return null;
return result;
}
public class ValidToken extends AsyncTask<String, String, String> {
ProgressDialog progressDialog;
HttpURLConnection connection = null;
BufferedReader reader = null;
Activity activity;
public ValidToken(Activity activity) {
this.activity = activity;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// display a progress dialog for good user experiance
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Please Wait");
progressDialog.setCancelable(false);
progressDialog.show();
}
@Override
protected String doInBackground(String... params) {
String result = null;
TokenViewModel token;
Gson gson;
try {
URL url = new URL(params[0]);
String authToken = params[1];
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", authToken);
connection.connect();
int statusCode = connection.getResponseCode();
if (statusCode == 200) {
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String jsonObjectHome = buffer.toString();
result = jsonObjectHome;
}
if (statusCode == 400){
token = new TokenViewModel();
token.setStatusCode(statusCode);
token.setMessage("fail please login again");
gson = new Gson();
result = gson.toJson(token);
}
if (statusCode == 404){
token = new TokenViewModel();
token.setStatusCode(statusCode);
token.setMessage("fail please login again");
gson = new Gson();
result = gson.toJson(token);
}
if (statusCode == 500){
token = new TokenViewModel();
token.setStatusCode(statusCode);
token.setMessage("fail please login again");
gson = new Gson();
result = gson.toJson(token);
}
} catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.cancel();
}
}


Download

Click here to download the source code

Please donate and support at https://www.paypal.me/Rajcoomar

Comments

Popular posts from this blog

Car Wash System vb.net

Face recognition using EmguCV 3.0 and typing pattern recognition

Student Information System - AngularJS , ASP.NET API, C#