Session认证和JWT(Json Web Token)

Token认证就是基于JWT

1.Session认证

1. 用户输入其登录信息

2. 服务器验证信息是否正确,并创建一个session,然后将其存储在数据库中

3. 服务器为用户生成一个sessionId,将具有sesssionId的Cookie将放置在用户浏览器中

4. 在后续请求中,会根据数据库验证sessionID,如果有效,则接受请求

5. 一旦用户注销应用程序,会话将在客户端和服务器端都被销毁

2.JWT认证

1. 用户输入其登录信息

2. 服务器验证信息是否正确,并返回已签名的token

3. token储在客户端,例如存在local storage或cookie中

4. 之后的HTTP请求都将token添加到请求头里

5. 服务器解码JWT,并且如果令牌有效,则接受请求

6. 一旦用户注销,令牌将在客户端被销毁,不需要与服务器进行交互一个关键是,令牌是无状态的。后端服务器不需要保存令牌或当前session的记录。

JWT里面只存放了一些不敏感的信息    比如一些重要的信息是用户发起请求 验证身份成功  再去 ProfileService 中把敏感信息放到HttpContext中   比如租户ID 等

服务器不保存生成Token   Token由三部分组成   根据客户端请求的Token  根据Token的前部和中部和密钥计算出来跟尾部相同 就验证通过  节约了服务器内存

http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

用VS 直接运行就报错  但是用VS Core打开 用dotnet run命令运行就没有报这个错误

IdentityServer4配置成功后  配置页面 localhost:xxxx/.well-known/openid-configuration

身份验证服务器需要添加IdentityServer4 包

客户端只需要添加IdentityServer4.AccessTokenValidation 包

进销存用的是密码模式

相当于经销存和protal    protal是身份验证服务器

经销存只是一个客户端  只需要添加IdentityServer4.AccessTokenValidation

1.用户在第三方客户端上操作的时候   想要访问接口地址       先去授权服务器认证

2.授权服务器通过验证后 会通过ProfileService  把用户信息包装成一个Claim 放返回

3.请求会加上返回的Claim  里面有用户信息 资料  token

注:如果是通过Postman测试  下面这样传参没问题      如果是通过前端来获取token   会报错400 Bad Request

都是post接口   通过抓包软件分析   传递的参数是

在前端需要对参数进行格式化   转成字符串  然后把Content-type改成application/x-www-form-urlencoded

    var param = '';
let data = {
client_id:'Consoleclient',
client_secret:'511536EF-F270-4058-80CA-1C89C192F69A',
grant_type:'client_credentials'
};
for (let property in data) {
param += `&${property}=${data[property]}`
}
param = param.substring(, param.length)
this.apiService.identityLoginAPI(param).then(res => {

Claim是用户身份  一个用户可以有多个身份

Scope是API资源的权限

1.客户端模式

进销存前端需要调用后端API  需要先到protal 的IdentityServer服务器  经过授权  拿到token   才能访问到后端API

  获取token 传参方式

  

2.密码模式

  需要输入真实账户和密码    这种模式body 可以设置为form-data 也可以设置为x-www-form-urlencoded

3.授权码模式

做一个统一的登陆界面  比如Pc端在Web上进行QQ登陆    然后比如登陆斗鱼的时候  可以用QQ账号密码登陆  也会跳转到QQ登陆的统一界面

搭建身份验证服务器

.Net Core的项目模版生成出来后 默认是https访问  在properties中的launchSettings.json中把sslport改为0

    "iisExpress": {
"applicationUrl": "http://localhost:5000",
"sslPort":
}

1.新建一个空web Api项目

  添加IdentityServer4包   这里用的版本都是2.1

  添加Config.cs配置类信息

  这是客户端模式配置

  

    public class Config
{
/// <summary>
/// 配置资源服务器
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetResource()
{
return new List<ApiResource>
{
new ApiResource("api","My Api")
};
}
/// <summary>
/// 配置客户端
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client()
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets ={
new Secret("secret".Sha256())
},
AllowedScopes = { "api"}
}
};
}
}

2.把IdentityServer添加到依赖注入配置项

        public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
          //添加开发证书
.AddDeveloperSigningCredential()
          //添加资源Api
.AddInMemoryApiResources(Config.GetResource())
          //添加客户端
.AddInMemoryClients(Config.GetClients()); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

3.在管道中添加身份验证服务器中间件

            app.UseIdentityServer();

4.启动的时候可能会报错   第一次配报错  第二次配没有报错 如果报错用Vs Code 打开  用dotnet run 命令运行

进入http://localhost:5000/.well-known/openid-configuration查看配置

"token_endpoint":"http://localhost:5000/connect/token",  这个地址就是获取token的地址

到这里  身份验证服务器搭建完毕      后面开始搭建客户端服务器  也就是接口服务器

1.新建一个Web Mvc空项目

  添加IdentityServer4.AccessTokenValidation包

  注入是身份验证服务器  这里的地址就是上面配的验证服务器地址

            services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(Options =>
{
Options.Authority = "http://localhost:5000";
Options.RequireHttpsMetadata = false;
Options.ApiName = "api"; });

2.在管道中开启授权验证中间件

app.UseAuthentication();

3.在需要保护的接口上添加[Authorize]特性

4.直接访问现在的接口 就会报错401  没有授权

先通过http://localhost:5000/connect/token 身份验证服务器拿到token 再去访问api接口

第二种 帐号密码模式

修改验证服务器的Config.cs

    public class Config
{
public static IEnumerable<ApiResource> GetResource()
{
return new List<ApiResource>
{
new ApiResource("api","My Api")
};
} public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
//客户端模式
new Client()
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets ={
new Secret("secret".Sha256())
},
AllowedScopes = { "api"}
},
//账号密码模式
new Client()
{
ClientId = "pwdClient",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets ={
new Secret("secret".Sha256())
},
AllowedScopes = { "api"}
}
};
}
/// <summary>
/// 添加一个模拟的帐号密码
/// </summary>
/// <returns></returns>
public static List<TestUser> GetTestUsers()
{
return new List<TestUser>{
new TestUser{
SubjectId = "",
Username="jcb",
Password = ""
}
};
}
}

2.把账号密码模式也进行注入  修改Startup.cs

            services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetResource())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetTestUsers());

这样就完成了帐号密码模式的配置

把账号密码模式改为动态的  通过数据库进行匹配

1.新增登录验证器类LoginValidator   继承IResourceOwnerPasswordValidator     接口有一个验证方法ValidateAsync

    public class LoginValidator : IResourceOwnerPasswordValidator
{
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
Customers customers = new Customers() { Name = context.UserName };
var res = await Login(customers);
if (res != null)
{
//GrantValidationResult实例根据构造函数传参不同来进行判断是否成功
context.Result = new GrantValidationResult(res.Id.ToString(), "password", (IEnumerable<Claim>)null, "local", (Dictionary<string, object>)null);
}
else
{
}
}
      //登录验证可以写这里
public async Task<Customers> Login(Customers customer)
{
using (MyDbContext db = new MyDbContext())
{
var res = db.customers.FirstOrDefault(t=>t.Name == customer.Name);
if (res != null)
{
return res;
}
return null;
}
}
}

2.在注册身份验证服务器的时候  把这个登录验证添加进来

.AddResourceOwnerValidator<LoginValidator>();

3.这样子执行的时候 默认会使用自带的DefaultProfileService  执行到内部IsActiveAsync()方法会报错     这个类在C:\Users\jiangchengbiao\.nuget\packages\identityserver4\2.1.0\lib\netstandard2.0\IdentityServer4.dll

解决方式:需要新建一个类 继承IProfileService  重写里面的IsActiveAsync()   然后再把这个注册到身份验证服务器上

    public class ProfileService : IProfileService
{
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
//通过第一次验证输出的账号密码 查询到租户ID等其他信息 添加到身份信息中
List<Claim> claims = Enumerable.ToList<Claim>(context.Subject.Claims);
claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "蒋承标"));
claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "浙江工贸"));
claims.Add(new Claim("http://jcb.org/identity/claims/tenantId", "租户ID"));
context.IssuedClaims = claims;
} public async Task IsActiveAsync(IsActiveContext context)
{
context.IsActive = true;
int num = await(Task<int>) Task.FromResult<int>();
}
}

4.把重写的ProfileService 注册到身份验证服务器上

        public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetResource())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetTestUsers())
.AddProfileService<ProfileService>()
.AddResourceOwnerValidator<LoginValidator>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

到这里就完成了  可以根据输入的帐号密码到数据库进行比对

然后在客户端(也就是经销商系统)启动JWT中间件   参数一定要是这个  还没具体去看

app.UseJwtTokenMiddleware("IdentityBearer");

    ctx.AuthenticateAsync会去身份验证服务器中把  各种身份信息查询出来  这里面有租户ID  用户姓名等 放到HttpContext中

    public static class JwtTokenMiddleware
{
public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app, string schema = JwtBearerDefaults.AuthenticationScheme)
{
return app.Use(async (ctx, next) =>
{
if (ctx.User.Identity?.IsAuthenticated != true)
{
var result = await ctx.AuthenticateAsync(schema);
if (result.Succeeded && result.Principal != null)
{
ctx.User = result.Principal;
}
} await next();
});
}
}

授权码模式

1.比如登录斗鱼,选择QQ登录,跳转到QQ统一登录页面并携带returnUrl

2.输入账号密码,同意授权,页面会回到returnUrl并携带Authorization Core

3.斗鱼向自己的服务发起登录请求传入Authorization Core

4.斗鱼后台服务通过Authorization Core参数向QQ发起获取AccessToken

5.获取AccessToken后,在向QQ发起获取用户信息

6.通过QQ返回的用户信息创建斗鱼账号,创建斗鱼服务颁发的Token返回给浏览器

第4-6步都是在后台完成的

open id connect

在授权码模式的第2步,QQ在返回的时候会直接返回用户信息和Access token,免去了后面的环节

使用OpenID Connect添加用户认证

1.客户端安装Nuget包

IdentityServer4.AccessTokenValidation

Microsoft.AspNetCore.Authentication.Abstractions

Microsoft.AspNetCore.Authentication.Cookies

Microsoft.AspNetCore.Authentication.OpenIdConnect

客户端代码

        public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SchoolDbContext>(d=>d.UseSqlServer(Configuration.GetConnectionString("Default"))); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false; options.ClientId = "mvc";
options.SaveTokens = true;
}); services.AddMvc();
}

IdentityServer4服务器配置的更多相关文章

  1. asp.net core IdentityServer4 实现 Client credentials(客户端凭证)

    前言 OAuth 2.0默认四种授权模式(GrantType) 授权码模式(authorization_code) 简化模式(implicit) 密码模式(resource owner passwor ...

  2. IdentityServer4 保护.net framework webapi

    一.IS4服务器配置 1.新建一个Asp.net  Core MVC程序,模板选择 Empty 2.Nuget添加 IdentityServer4,我这里添加的是2.5.3 3.添加Config文件, ...

  3. IdentityServer4 使用OpenID Connect添加用户身份验证

    使用IdentityServer4 实现OpenID Connect服务端,添加用户身份验证.客户端调用,实现授权. IdentityServer4 目前已更新至1.0 版,在之前的文章中有所介绍.I ...

  4. IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习保护API

    IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习之保护API. 使用IdentityServer4 来实现使用客户端凭据保护ASP.N ...

  5. Linux服务器配置之加载硬盘

    Linux服务器配置之加载硬盘 1.修改密码 passwd 2.测试密码是否成功 3.查看硬盘信息 fdisk –l 4.格式化分区 fdisk /dev/vdb 5.查看分区 6.快速格式化/dev ...

  6. Windows Server 2008 R2 WEB服务器配置系列文章索引

    最近这段时间趁天翼云1元主机活动,购买了一个1元主机,主要是为了写一些服务器配置的教程. 已经完成如下几篇文章,送给大家. 国内云主机比较 天翼云/阿里云/腾讯云 Windows Server 200 ...

  7. Window下python2.7+Apache+mod_wsgi+Django服务器配置

    前言:试着使用python搭建一个网页,分别在windows下和linux下,本篇文章主要讲解Window下python+Apache+mod_wsgi+Django服务器配置过程中遇见的问题和解决方 ...

  8. Samba服务器配置

    Samba服务器配置流程: (1)安装samba服务器先用#rpm -ivh samba-列出与samba有关的rpm包然后选择第一个包,用tab键补齐文件名 (2)创建新用户和其密码#useradd ...

  9. 【原创】我所理解的自动更新-外网web服务器配置

    ClientDownload和ClientUpdate共享渠道配置信息: channel-0.php //以appstore的渠道为例 <?php define('APPNAME', 'TOKE ...

随机推荐

  1. 利用XML语法 SQL 列转行

    --行转列 固定xml语法 declare @xml xml ; set @xml=cast('<v>2</v><v>4</v><v>3&l ...

  2. EasyUI Tree节点拖动到指定容器

    效果图:将tree节点拖动到指定的DIV中,结果显示节点的id和text 代码: <!DOCTYPE html> <html> <head> <meta ch ...

  3. linux命令 网络篇

    linux常用命令 netstat 语法(命令)  主要查看端口状态 netstat  语法 netstat -t/tcp 显示Tcp传输协议连线状况; netstat -u/udp 显示UDP传输协 ...

  4. js 限制输入框只能输入数字的问题

    常规情况下,input设置为 type=‘number’  可以避免汉字,字符,字母,空格的输入,但是不能避免小减号 以及小键盘的减号-,加号+的输入, 可以考虑 监控 输入框的oninput事件,方 ...

  5. Eclipse 02: 安装SVN插件

    1.下载最新的Eclipse,我的版本是3.7.2 indigo(Eclipse IDE for Java EE Developers)版    如果没有安装的请到这里下载安装:http://ecli ...

  6. 1、js比较日期的大小

    ① html <div class="ptb10"><span>共享开始时间:</span><input type="text& ...

  7. 1_01 vue的双向绑定

    听说vue1是双向绑定,不过现在Vue2不能直接双向绑定,需要设置绑定. 一.常见的是input表单的v-model const component = { template: ` <div&g ...

  8. C语言中tm结构体

    struct tm { int tm_sec; /* Seconds. [0-60] (1 leap second) */ int tm_min; /* Minutes. [0-59] */ int ...

  9. C++提供的四种新式转换--const_cast dynamic_cast reinterpret_cast static_cast

    关于强制类型转换的问题,许多书都讨论过,写的最具体的是C++之父的<C++的设计和演化>. 最好的解决方法就是不要使用C风格的强制类型转换,而是使用标准C++的类型转换符:static_c ...

  10. hibernate重要知识点总结

    一.使用注解方式-----实体和表之间的映射 配置spring的applicationContext.xml文件: <bean id="sessionFactory" cla ...