在 MVC .Net Framework 中创建用于令牌身份验证的单例

Create a singleton in MVC .Net Framework for token authentication

我有几个问题,我正在尝试实施一种安全方式来为我的所有 Web api 调用保留令牌。我正在学习教程 Here。这是我已经或未能实施的问题

  1. 如何在 MVC5 .Net Framework 4.7 应用程序中实现单例(我在我的网络中使用 autofac 作为 DI api(我有服务层、领域层和数据层)但不确定我要做什么需要 mvc5.
  2. 这是否意味着我所有的应用程序控制器现在都需要一个构造函数并实现 IApiHelper 接口来调用任何 Web 应用程序
  3. 通过转换为接口,我无法再接缝调用我的 readAsync,我的替代方案是什么。

这就是我用 IHelper 给我的学生 api 打电话的方式,但是我在读取异步时遇到问题。

public class StudentsController : Controller
{
    private IApiHelper apiClient;
    public StudentsController(IApiHelper _helper)
    {
        apiClient = _helper;
    }
    // GET: Students
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult GetStudents()
    {
        List<StudentModel> listStudent = new List<StudentModel>();

        var responseTask = apiClient.GetAsync("Students");
        responseTask.Wait();

        var result = responseTask.Result;
        if (result.IsSuccessStatusCode)
        {
            var readTask = result.Content.ReadAsAsync<List<StudentModel>>();
            readTask.Wait();

            listStudent = readTask.Result;
        }
        else
        {
            throw new Exception(result.ReasonPhrase);
        }

        return Json(listStudent, JsonRequestBehavior.AllowGet);
    }
}

这基本上就是我在 IApiHelper 上实现的。

My interface
    public interface IApiHelper
    {
        Task<AuthenticatedUser> Authenticate(string username, string password);
    }

这是实现

    public class ApiHelper : IApiHelper
    {
        private HttpClient apiClient;

        public ApiHelper()
        {
            InitializeClient();
        }

        public void InitializeClient()
        {
            string ApiBaseUrl = ConfigurationManager.AppSettings["api"];
            apiClient = new HttpClient();
            apiClient.BaseAddress = new Uri(ApiBaseUrl);
            apiClient.DefaultRequestHeaders.Accept.Clear();
            apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

        public async Task<AuthenticatedUser> Authenticate(string username, string password)
        {
            var data = new FormUrlEncodedContent(new[] {
                new KeyValuePair<string, string>("grant_type", "password"),
                new KeyValuePair<string, string>("username", username),
                new KeyValuePair<string, string>("password", password)
            });

            using (HttpResponseMessage response = await apiClient.PostAsync("/Token", data))
            {
                if (response.IsSuccessStatusCode)
                {
                    var result = await response.Content.ReadAsAsync<AuthenticatedUser>();
                    return result;
                }
                else
                {
                    throw new Exception(response.ReasonPhrase);
                }
            }

        }
    }

问题不在于 Autofac、DI 或单例 - 它在于您的接口定义。根据您发布的内容,您的界面是:

public interface IApiHelper
{
    Task<AuthenticatedUser> Authenticate(string username, string password);
}

从字面上看,此接口实例上的唯一方法Authenticate

因此,当您的代码中包含此内容时:

var responseTask = apiClient.GetAsync("Students");

因为 apiClient 是实现 IApiHelperApiHelper,所以没有 GetAsync 方法。如果要在IApiHelper上调用GetAsync,则需要将该方法添加到接口中,然后在ApiHelper.

中实现它
public interface IApiHelper
{
    Task<HttpResponseMessage> GetAsync(string requestUri);
    Task<AuthenticatedUser> Authenticate(string username, string password);
}

但是,我不知道如果我允许使用 GETPOST 操作调用任意端点,我个人是否一定会选择接口路由。

相反,我可能会考虑与您的助手一起向 HttpClient 添加扩展方法。

public static class HttpClientExtensions
{
    public async Task<AuthenticatedUser> Authenticate(this HttpClient apiClient, string username, string password)
    {
        var data = new FormUrlEncodedContent(new[] {
            new KeyValuePair<string, string>("grant_type", "password"),
            new KeyValuePair<string, string>("username", username),
            new KeyValuePair<string, string>("password", password)
        });

        using (HttpResponseMessage response = await apiClient.PostAsync("/Token", data))
        {
            if (response.IsSuccessStatusCode)
            {
                var result = await response.Content.ReadAsAsync<AuthenticatedUser>();
                return result;
            }
            else
            {
                throw new Exception(response.ReasonPhrase);
            }
        }
    }
}

这将允许您调用 apiClient.Authenticate(username, password),就好像它是 HttpClient 对象上的一个方法一样,但它不会强制您重新实现所有 get/post/whatever 操作在界面中。