系列目录

循序渐进学.Net Core Web Api开发系列目录

本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi

一、概述

本篇介绍Web系统的应用安全,主要涉及用户的身份认证和访问权限问题。

大部分web应用习惯采用Session来保存用户认证信息,对于WebApi而言,调用者不一定是Web浏览器,可能是Android、iOS客户端,可能是微信小程序,也可能是客户端程序等等,这些客户端模拟构造cookie、存储或传递sessionid都不是太方便,这种情况下,采用令牌(tockenid)的方式进行授权管理就显得比较方便,唯一不方便的就是每次调用都要传递tockenid。

基本流程如下:

1、调用登陆接口,通过正确的用户名和密码活动TockenID;

2、通过TockenID调用其他业务接口。

二、基本使用

1、处理用户登陆的Controller

        [HttpPost("login")]
public ResultObject Login(string loginname,string password)
{
try
{
User user = _context.Users
.AsNoTracking()
.Where(a => a.LoginName == loginname && a.Password == password)
.Single(); String tockenid = Tocken.GetTockenID(); _cache.Set(tockenid, user, new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds())); return new ResultObject
{
state = ResultState.Success,
result = tockenid
};
}
catch(InvalidOperationException ex)
{
return new ResultObject
{
state = ResultState.Exception,
ExceptionString = "未找到匹配的数据"
};
}
}

首先在数据库寻找匹配的用户信息,如果验证成功就以TockenID为主键把用户信息存入缓存,并设置过期时间(示例代码中过期时间为20秒),然后返回TockenID。

2、在业务Controller中根据传入TockenID的进行用户认证。

[HttpGet]
public ResultObject GetAllArticles(string tockenid)
{
User user = null;
if(!_cache.TryGetValue(tockenid,out user))
{
return new ResultObject
{
state = ResultState.Fail,
ExceptionString = "请登陆"
};
} List<Article> articles = _context.Articles
.AsNoTracking()
.ToList<Article>(); return new ResultObject
{
state = ResultState.Success,
result = articles
};
}

三、采用中间件进行用户认证

因为每个业务Controller都需要进行认证,所以按上述方法就比较麻烦了,我们做个中间件来进行统一身份验证

namespace SaleService.System.Middleware
{
public class UserAuthenticationMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
private readonly IMemoryCache _cache; public UserAuthenticationMiddleware(RequestDelegate next, ILogger<UserAuthenticationMiddleware> logger, IMemoryCache memoryCache)
{
_next = next;
_logger = logger;
_cache = memoryCache;
} public async Task Invoke(HttpContext context)
{
//如果是登陆接口就不需要验证Tocken
if (context.Request.Path.ToString().ToLower().StartsWith("/api/user/login"))
{
await _next(context);
return;
} if (context.Request.Path.ToString().ToLower().StartsWith("/api/"))
{
string tockenid = context.Request.Query["tockenid"]; if (tockenid == null)
{
var result = new ResultObject
{
state = ResultState.Exception,
ExceptionString = "Need tockenid"
}; context.Response.ContentType = "application/json; charset=utf-8";
context.Response.WriteAsync(JsonConvert.SerializeObject(result));
return;
} User user = null;
if (!_cache.TryGetValue(tockenid, out user))
{
context.Response.StatusCode = ;
context.Response.ContentType = "application/json; charset=utf-8";
context.Response.WriteAsync("Invalidate tockenid(用户认证失败)");
return;
}
}
await _next(context);
}
} public static class UserAuthenticationMiddlewareExtensions
{
public static IApplicationBuilder UseUserAuthentication(this IApplicationBuilder builder)
{
return builder.UseMiddleware<UserAuthenticationMiddleware>();
}
}
}

该中间件直接截取Request中的tockid进行验证,如果验证不通过就直接返回“短路”其他中间件,所以在使用时需要放在MVC中间件前面。

public class Startup
{
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials());
app.UseStaticFiles();
app.UseUserAuthentication();//要放在UseMvc前面
app.UseMvcWithDefaultRoute();
}
}

此时业务Controller就比较简单干净了,专心做业务就可以了

      [HttpGet]
public ResultObject GetAllArticles(string tockenid)
{
List<Article> articles = _context.Articles
.AsNoTracking()
.ToList<Article>(); return new ResultObject
{
state = ResultState.Success,
result = articles
};
}

此时,如果需要,仍可以通过tockenid获取用户信息。

四、关于访问的权限

此时用户需要登陆才能访问受限业务Api,但对用户权限并没有约束,实际应用时需要建立角色,通过用户于角色对应关系和角色与资源的对应关系,确认用户可以访问的资源列表。

五、几点需要优化的地方

这里描述了通过TockenID进行用户认证的基本思路,实际应用时还有很多需要改善的地方:

1、对于一些公开应用是不需要验证的,如果在中间件中通过if来判断路径就显得比较丑陋,是否可以通过给这些Controller加上相关的特性来进行标识?

2、如何方便地判断用户与资源的对应关系?

3、Controller中通过tockenid获取用户信息的方法能否封装一下?

这些问题暂时还没有考虑充分,以后有机会完善一下。

循序渐进学.Net Core Web Api开发系列【15】:应用安全的更多相关文章

  1. 循序渐进学.Net Core Web Api开发系列【0】:序言与目录

    一.序言 我大约在2003年时候开始接触到.NET,最初在.NET framework 1.1版本下写过代码,曾经做过WinForm和ASP.NET开发.大约在2010年的时候转型JAVA环境,这么多 ...

  2. 循序渐进学.Net Core Web Api开发系列【16】:应用安全续-加密与解密

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 应用安全除 ...

  3. 循序渐进学.Net Core Web Api开发系列【14】:异常处理

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍异 ...

  4. 循序渐进学.Net Core Web Api开发系列【13】:中间件(Middleware)

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...

  5. 循序渐进学.Net Core Web Api开发系列【12】:缓存

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...

  6. 循序渐进学.Net Core Web Api开发系列【11】:依赖注入

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...

  7. 循序渐进学.Net Core Web Api开发系列【10】:使用日志

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.本篇概述 本篇介 ...

  8. 循序渐进学.Net Core Web Api开发系列【9】:常用的数据库操作

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇描述一 ...

  9. 循序渐进学.Net Core Web Api开发系列【8】:访问数据库(基本功能)

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇讨论如 ...

随机推荐

  1. D. Recovering BST Codeforces Round #505 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)

    http://codeforces.com/contest/1025/problem/D 树 dp 优化 f[x][y][0]=f[x][z][1] & f[z+1][y][0] ( gcd( ...

  2. P2513 [HAOI2009]逆序对数列

    P2513 [HAOI2009]逆序对数列 题目描述 对于一个数列{ai},如果有iaj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那 ...

  3. 网络报错:“The connection is not for this device.”

    网络报错:“The connection is not for this device.” 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 记得在前几天工作的时候,有一个同时通过微信 ...

  4. 小贾漫谈——Java反射

    一.Class的API 二.测试使用的JavaBean class Admin{ //字段 public String userName; public String pwd; private int ...

  5. redis支持的数据结构

    redis数据库里面的每个键值对都是由对象组成的. 其中数据库键的值总是字符串对象. 数据库的值则可以是字符串对象(String),列表对象(list),哈希对象(Hash),集合对象(Set),有序 ...

  6. Linux-Xshell会话保持

    1.Xshell客户端设置 2.服务端设置 修改/etc/ssh/sshd_config文件,找到 ClientAliveInterval 0和ClientAliveCountMax 3并将注释符号( ...

  7. Google Email 帐户泄露

    最初爆出来的网站是:https://forum.btcsec.com/index.php?/topic/9426-gmail-meniai-parol/,是一个俄罗斯论坛,然后..就流传开来了... ...

  8. codeforces 235 div2 B. Sereja and Contests

    Sereja is a coder and he likes to take part in Codesorfes rounds. However, Uzhland doesn't have good ...

  9. HDU 1176 免费馅饼 DP类似数塔题

    解题报告: 小明走在一条小路上,这条小路的长度是10米,从左到右依次是0到10一共十个点,现在天上会掉馅饼,给出馅饼掉落的坐标和时间,一开始小明的位置是在坐标为5的位置, 他每秒钟只能移动一米的距离, ...

  10. 第11月第21天 php引用 codeigniter cakephp

    1. class CI_Controller { private static $instance; /** * Constructor */ public function __construct( ...