iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >ASP.NET Core 6.0怎么添加JWT认证和授权功能
  • 754
分享到

ASP.NET Core 6.0怎么添加JWT认证和授权功能

2023-06-30 04:06:18 754人浏览 安东尼
摘要

本篇内容介绍了“asp.net Core 6.0怎么添加Jwt认证和授权功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成

本篇内容介绍了“asp.net Core 6.0怎么添加Jwt认证和授权功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

相关名词

Authentication 和 Authorization 长得很像,傻傻分不清楚。

Authentication(认证):标识用户的身份,一般发生在登录的时候。

Authorization(授权):授予用户权限,指定用户能访问哪些资源;授权的前提是知道这个用户是谁,所以授权必须在认证之后。

认证(Authentication)

基本步骤

  • 安装相关 Nuget 包:Microsoft.Aspnetcore.Authentication.JwtBearer

  • 准备配置信息(密钥等)

  • 添加服务

  • 调用中间件

  • 实现一个 JwtHelper,用于生成 Token

  • 控制器限制访问(添加 Authorize 标签)

1 安装 Nuget 包

安装 Microsoft.AspNetCore.Authentication.JwtBearer

在程序包管理器控制台中:

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 6.0.1

2 准备配置信息

在 appsetting.JSON 中,添加一个 Jwt 节点

"Jwt": {    "SecreTKEy": "lisheng741@qq.com",    "Issuer": "WEBAppIssuer",    "Audience": "WebAppAudience"}

3 添加服务

在 Program.cs 文件中注册服务。

// 引入所需的命名空间using Microsoft.AspNetCore.Authentication.JwtBearer;using Microsoft.IdentityModel.Tokens;using System.Text;// ……var configuration = builder.Configuration;// 注册服务builder.Services.AddAuthentication(options =>{    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(options =>{    options.TokenValidationParameters = new TokenValidationParameters()    {        ValidateIssuer = true, //是否验证Issuer        ValidIssuer = configuration["Jwt:Issuer"], //发行人Issuer        ValidateAudience = true, //是否验证Audience        ValidAudience = configuration["Jwt:Audience"], //订阅人Audience        ValidateIssuerSigningKey = true, //是否验证SecurityKey        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"])), //SecurityKey        ValidateLifetime = true, //是否验证失效时间        ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值,解决服务器端时间不同步问题(秒)        RequireExpirationTime = true,    };});

4 调用中间件

调用 UseAuthentication(认证),必须在所有需要身份认证的中间件前调用,比如 UseAuthorization(授权)。

// ……app.UseAuthentication();app.UseAuthorization();// ……

5 JwtHelper 类实现

主要是用于生成 JWT 的 Token。

using Microsoft.IdentityModel.Tokens;using System.IdentityModel.Tokens.Jwt;using System.Security.Claims;using System.Text;namespace Testwebapi;public class JwtHelper{    private readonly IConfiguration _configuration;    public JwtHelper(IConfiguration configuration)    {        _configuration = configuration;    }    public string CreateToken()        // 1. 定义需要使用到的Claims        var claims = new[]        {            new Claim(ClaimTypes.Name, "u_admin"), //HttpContext.User.Identity.Name            new Claim(ClaimTypes.Role, "r_admin"), //HttpContext.User.IsInRole("r_admin")            new Claim(JwtReGISteredClaimNames.Jti, "admin"),            new Claim("Username", "Admin"),            new Claim("Name", "超级管理员")        };        // 2. 从 appsettings.json 中读取SecretKey        var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"]));        // 3. 选择加密算法        var alGorithm = SecurityAlgorithms.HMacSha256;        // 4. 生成Credentials        var signinGCredentials = new SigningCredentials(secretKey, algorithm);        // 5. 根据以上,生成token        var jwtSecurityToken = new JwtSecurityToken(            _configuration["Jwt:Issuer"],     //Issuer            _configuration["Jwt:Audience"],   //Audience            claims,                          //Claims,            DateTime.Now,                    //notBefore            DateTime.Now.AddSeconds(30),    //expires            signingCredentials               //Credentials        );        // 6. 将token变为string        var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);        return token;}

该 JwtHelper 依赖于 IConfiguration(为了读取配置文件),将 JwtHelper 的创建交由 DI 容器,在 Program.cs 中添加服务:

var configuration = builder.Configuration;builder.Services.AddSingleton(new JwtHelper(configuration));

将 JwtHelper 注册为单例模式。

6 控制器配置

新建一个 AccountController,以构造函数方式注入 JwtHelper,添加两个 Action:GetToken 用于获取 Token,GetTest 打上 [Authorize] 标签用于验证认证。

using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.mvc;namespace TestWebapi.Controllers;[Route("api/[controller]/[action]")][ApiController]public class AccountController : ControllerBase{    private readonly JwtHelper _jwtHelper;    public AccountController(JwtHelper jwtHelper)    {        _jwtHelper = jwtHelper;    }    [HttpGet]    public ActionResult<string> GetToken()    {        return _jwtHelper.CreateToken();    }    [Authorize]    [HttpGet]    public ActionResult<string> GetTest()    {        return "Test Authorize";    }}

7 测试调用

方式一:通过 Postman、Apifox 等接口调试软件调试

使用 Postman 调用 /api/Account/GetToken 生成 Token

在调用 /api/Account/GetTest 时传入 Token,得到返回结果

方式二:在浏览器控制台调试

调试 /api/Account/GetToken

var xhr = new XMLHttpRequest();xhr.addEventListener("readystatechange", function() {   if(this.readyState === 4) {      console.log(token = this.responseText); //这里用了一个全局变量 token,为下一个接口服务   }});xhr.open("GET", "/api/Account/GetToken");xhr.send();

调试 /api/Account/GetTest

var xhr = new XMLHttpRequest();xhr.addEventListener("readystatechange", function() {   if(this.readyState === 4) {      console.log(this.status, this.responseText); //this.status为响应状态码,401为无认证状态   }});xhr.open("GET", "/api/Account/GetTest");xhr.setRequestHeader("Authorization",`Bearer ${token}`); //附带上 tokenxhr.send();

授权(Authorization)

注意:授权必须基于认证,即:若没有完成上文关于认证的配置,则下面的授权是不会成功的。

授权部分,将先介绍相关标签、授权方式,再介绍基于策略的授权。这三部分大致的内容如下描述:

相关标签:Authorize 和 AllowAnonymous

授权方式:介绍 Policy、Role、Scheme 的基本内容

基于策略(Policy)的授权:深入 Policy 授权方式

相关标签(Attribute)

授权相关标签具体请查考官方文档简单授权

[Authorize]

打上该标签的 Controller 或 Action 必须经过认证,且可以标识需要满足哪些授权规则。

授权规则可以是 Policy(策略)、Roles(角色) 或 AuthenticationSchemes(方案)。

[Authorize(Policy = "", Roles ="", AuthenticationSchemes ="")]

[AllowAnonymous]

允许匿名访问,级别高于 [Authorize] ,若两者同时作用,将生效 [AllowAnonymous]

授权方式

基本上授权只有:Policy、Role、Scheme 这3种方式,对应 Authorize 标签的3个属性。

1 Policy(策略)

推荐的授权方式,在 ASP.net core 的官方文档提及最多的。一个 Policy 可以包含多个要求(要求可能是 Role 匹配,也可能是 Claims 匹配,也可能是其他方式。)

下面举个基础例子(说是基础例子,主要是基于 Policy 的授权方式可以不断深入追加一些配置):

在 Program.cs 中,添加两条 Policy:

policy1 要求用户拥有一个 Claim,其 ClaimType 值为 EmployeeNumber。

policy2 要求用户拥有一个 Claim,其 ClaimType 值为 EmployeeNumber,且其 ClaimValue 值为1、2、3、4 或 5。

builder.Services.AddAuthorization(options => {    options.AddPolicy("policy1", policy => policy.RequireClaim("EmployeeNumber"));    options.AddPolicy("policy2", policy => policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));})

在控制器中添加 [Authorize] 标签即可生效:

[Authorize(Policy = "policy1")]public class TestController : ControllerBase

或在控制器的 Action 上:

public class TestController : ControllerBase{    [Authorize(Policy = "policy1")]    public ActionResult<string> GetTest => "GetTest";}

2 Role(角色)

基于角色授权,只要用户拥有角色,即可通过授权验证。

在认证时,给用户添加角色相关的 Claim ,即可标识用户拥有的角色(注:一个用户可以拥有多个角色的 Claim),如:

new Claim(ClaimTypes.Role, "admin"),new Claim(ClaimTypes.Role, "user")

在 Controller 或 Action 中:

[Authorize(Roles = "user")]public class TestController : ControllerBase{    public ActionResult<string> GetUser => "GetUser";        [Authorize(Roles = "admin")] //与控制器的Authorize叠加作用,除了拥有user,还需拥有admin    public ActionResult<string> GetAdmin => "GetAdmin";        [Authorize(Roles = "user,admin")] //user 或 admin 其一满足即可    public ActionResult<string> GetUserOrAdmin => "GetUserOrAdmin";}

3 Scheme(方案)

方案如:Cookies 和 Bearer,当然也可以是自定义的方案。

由于这种方式不常用,这里不做展开,请参考官方文档按方案限制标识。

基于策略(Policy)的授权

上面已经提及了一个基于策略授权的基础例子,下面将继续深入这种授权方式。

1 授权过程

在不断深入 Policy 这种方式的授权之前,有必要将授权的过程描述一下。授权过程描述建议结合源码查看,这样能更清楚其中的作用。当然,这一部分是比较难懂,笔者表述可能也不够清晰,而这一部分对于完成授权的配置也不会有影响,故而如果读者看不明白或无法理解,可以暂且跳过,不必纠结。

建议看一下ASP.net core使用JWT认证授权的方法这篇文章,文章将授权相关的源码整理出来了,并说明了其中的关系。

这里简单梳理一下:

与授权相关的 interface 和 class 如下:

IAuthorizationService #验证授权的服务,主要方法AuthorizeAsyncDefaultAuthorizationService #IAuthorizationService的默认实现IAuthorizationHandler #负责检查是否满足要求,主要方法HandleAsyncIAuthorizationRequirement #只有属性,没有方法;用于标记服务,以及用于追踪授权是否成功的机制。AuthorizationHandler<TRequirement> #主要方法HandleRequirementAsync

这些 interface 和 class 的关系以及授权过程是这样的:

DefaultAuthorizationService 实现 IAuthorizationServiceAuthorizeAsync 方法。

AuthorizeAsync 方法会获取到所有实现了 IAuthorizationHandler 的实例,并循环调用所有实例的 HandleAsync 方法检查是否满足授权要求,如果有任一一个 HandleAsync 返回了 Fail 则将结束循环(细节请参考官方文档处理程序返回结果),并禁止用户访问。

IAuthorizationHandler 的作用如上一点所述,提供了一个 HandleAsync 方法,用于检查授权。

IAuthorizationRequirement 是一个要求,主要是配合 AuthorizationHandler<TRequirement> 使用。

AuthorizationHandler<TRequirement> 实现了 IAuthorizationHandlerHandleAsync 方法,并提供了一个 HandleRequirementAsync 的方法。HandleRequirementAsync 用于检查 Requirement(要求)是否满足。HandleAsync 的默认实现为获取所有实现 TRequirement 的请求(且该请求由 Policy 添加进列表里),循环调用 HandleRequirementAsync,检查哪个要求(Requirement)能满足授权。

简述一下:

[Authorize] 标签生效时,调用的是 IAuthorizationServiceAuthorizeAsync(由 DefaultAuthorizationService 实现)。

AuthorizeAsync 会去调用所有 IAuthorizationHandlerHandleAsync (由 AuthorizationHandler<TRequirement> 实现)。

HandleAsync 会去调用 AuthorizationHandler<TRequirement>HandleRequirementAsync 的方法。

注意:这里只是列出了主要的接口和类,部分没有列出,如:IAuthorizationHandlerProvider(这个接口的默认实现 DefaultAuthorizationHandlerProvider,主要是用于收集 IAuthorizationHandler 并返回 IEnumerable<IAuthorizationHandler>

2 实现说明

IAuthorizationService 已默认实现,不需要我们做额外工作。

IAuthorizationHandlerAuthorizationHandler<TRequirement> 实现。

所以我们要做的,是:

第一步,准备 Requirement 实现 IAuthorizationRequirement

第二步,添加一个 Handler 程序继承 AuthorizationHandler<TRequirement> 并重写 HandleRequirementAsync 方法

3 定义权限项

在实现 Requirement 之前,我们需要先定义一些权限项,主要用于后续作为 Policy 的名称,并传入 我们实现的 Requirement 之中。

public static class UserPermission{    public const string User = "User";    public const string UserCreate = User + ".Create";    public const string UserDelete = User + ".Delete";    public const string UserUpdate = User + ".Update";}

如上,定义了“增”、“删”、“改”等权限,其中 User 将拥有完整权限。

4 实现 Requirement

public class PermissionAuthorizationRequirement : IAuthorizationRequirement{    public PermissionAuthorizationRequirement(string name)    {        Name = name;    }    public string Name { get; set; }}

使用 Name 属性表示权限的名称,与 UserPermission 中的常量对应。

5 实现授权处理程序 Handler

这里假定用户的 Claim 中 ClaimType 为 Permission 的项,如:

new Claim("Permission", UserPermission.UserCreate),new Claim("Permission", UserPermission.UserUpdate)

如上,标识该用户用户 UserCreate 和 UserUpdate 的权限。

注意:当然,实际程序我们肯定不是这样实现的,这里只是简易示例。

接着,实现一个授权 Handler:

public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionAuthorizationRequirement>{    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement)    {        var permissions = context.User.Claims.Where(_ => _.Type == "Permission").Select(_ => _.Value).ToList();        if (permissions.Any(_ => _.StartsWith(requirement.Name)))        {            context.Succeed(requirement);        }        return Task.CompletedTask;    }}

运行 HandleRequirementAsync 时,会将用户的 Claim 中 ClaimType 为 Permission 的项取出,并获取其 Value 组成一个 List<string>

接着验证 Requirement 是否满足授权,满足则运行 context.Succeed

6 添加授权处理程序

在 Program.cs 中,将 PermissionAuthorizationHandler 添加到 DI 中:

builder.Services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();

7 添加授权策略

builder.Services.AddAuthorization(options =>{    options.AddPolicy(UserPermission.UserCreate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(UserPermission.UserCreate)));    options.AddPolicy(UserPermission.UserUpdate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(UserPermission.UserUpdate)));    options.AddPolicy(UserPermission.UserDelete, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(UserPermission.UserDelete)));});

8 控制器配置

控制器如下:

[Route("api/[controller]/[action]")][ApiController]public class UserController : ControllerBase{    [HttpGet]    [Authorize(UserPermission.UserCreate)]    public ActionResult<string> UserCreate() => "UserCreate";    [HttpGet]    [Authorize(UserPermission.UserUpdate)]    public ActionResult<string> UserUpdate() => "UserUpdate";    [HttpGet]    [Authorize(UserPermission.UserDelete)]    public ActionResult<string> UserDelete() => "UserDelete";}

基于上面的假定,用户访问接口的情况如下:

/api/User/UserCreate #成功/api/User/UserUpdate #成功/api/User/UserDelete #403无权限

至此,基于策略(Policy)的授权其实已经基本完成。

接下去的内容,将是对上面一些内容的完善或补充。

完善:实现策略提供程序 PolicyProvider

一般添加授权策略如下是在 Program.cs 中,方式如下:

builder.Services.AddAuthorization(options =>{    options.AddPolicy("policy", policy => policy.RequireClaim("EmployeeNumber"));});

通过 AuthorizationOptions.AddPolicy 添加授权策略这种方式不灵活,无法动态添加。

通过实现 IAuthorizationPolicyProvider 并添加到 DI 中,可以实现动态添加 Policy。

IAuthorizationPolicyProvider 的默认实现为 DefaultAuthorizationPolicyProvider

实现一个 PolicyProvider 如下:

public class TestAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider, IAuthorizationPolicyProvider{    public Test2AuthorizationPolicyProvider(IOptions<AuthorizationOptions> options) : base(options) {}    public new Task<AuthorizationPolicy> GetDefaultPolicyAsync()        => return base.GetDefaultPolicyAsync();    public new Task<AuthorizationPolicy?> GetFallbackPolicyAsync()        return base.GetFallbackPolicyAsync();    public new Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)    {        if (policyName.StartsWith(UserPermission.User))        {            var policy = new AuthorizationPolicyBuilder("Bearer");            policy.AddRequirements(new PermissionAuthorizationRequirement(policyName));            return Task.FromResult<AuthorizationPolicy?>(policy.Build());        }        return base.GetPolicyAsync(policyName);    }}

注意:自定义的 TestAuthorizationPolicyProvider 必须实现 IAuthorizationPolicyProvider,否则添加到 DI 时会不生效。

在 Program.cs 中,将自定义的 PolicyProvider 添加到 DI 中:

builder.Services.AddSingleton<IAuthorizationPolicyProvider, TestAuthorizationPolicyProvider>();

注意:只会生效最后一个添加的 PolicyProvider。

补充:自定义 AuthorizationMiddleware

自定义 AuthorizationMiddleware 可以:

  • 返回自定义的响应

  • 增强(或者说改变)默认的 challenge 或 forbid 响应

补充:MiniApi 的授权

在 MiniApi 中几乎都是形如 MapGet() 的分支节点,这类终结点无法使用 [Authorize] 标签,可以用使用 RequireAuthorization("Something") 进行授权,如:

app.MapGet("/helloworld", () => "Hello World!")    .RequireAuthorization("AtLeast21");

“ASP.net Core 6.0怎么添加JWT认证和授权功能”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: ASP.NET Core 6.0怎么添加JWT认证和授权功能

本文链接: https://www.lsjlt.com/news/327318.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • ASP.NET Core 6.0 添加 JWT 认证和授权功能
    目录序言相关名词认证(Authentication)基本步骤1 安装 Nuget 包2 准备配置信息3 添加服务4 调用中间件5 JwtHelper 类实现6 控制器配置7 测试调用...
    99+
    2024-04-02
  • ASP.NET Core 6.0怎么添加JWT认证和授权功能
    本篇内容介绍了“ASP.NET Core 6.0怎么添加JWT认证和授权功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成...
    99+
    2023-06-30
  • .NET Core怎么实现Cookie和JWT混合认证、授权
    本篇内容介绍了“.NET Core怎么实现Cookie和JWT混合认证、授权”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言为防...
    99+
    2023-06-26
  • .NET Core支持Cookie和JWT混合认证、授权的方法
    目录前言Cookie认证JWT认证滑动过期思考扩展总结前言 为防止JWT Token被窃取,我们将Token置于Cookie中,但若与第三方对接,调用我方接口进行认证、授权此时仍需将...
    99+
    2024-04-02
  • asp.net core3.1cookie和jwt混合认证授权实现多种身份验证方案
    目录认证授权 身份认证 授权 默认授权选择授权总结 开发了一个公司内部系统,使用asp.net core 3.1。在开发用户认证授权使用的是简单的cookie认证方式,然后开发好了要...
    99+
    2024-04-02
  • ASP.NET Core中策略授权和ABP授权怎么用
    小编给大家分享一下ASP.NET Core中策略授权和ABP授权怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!ASP.NET Core 中的策略授...
    99+
    2023-06-29
  • Golang怎么使用JWT进行认证和加密
    这篇“Golang怎么使用JWT进行认证和加密”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Golang怎么使用JWT进行认...
    99+
    2023-07-05
  • SpringBoot中怎么实现安全认证和授权
    在Spring Boot中,可以使用Spring Security实现安全认证和授权。Spring Security是一个强大且高度...
    99+
    2024-03-07
    SpringBoot
  • Vue怎么添加手机验证码组件功能
    本篇内容主要讲解“Vue怎么添加手机验证码组件功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Vue怎么添加手机验证码组件功能”吧!什么是组件:组件是Vue.js最强大的功能之一。组件可以扩展...
    99+
    2023-07-04
  • vue.js和sql怎么实现添加用户功能
    这篇文章给大家分享的是有关vue.js和sql怎么实现添加用户功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Vue的优点Vue具体轻量级框架、简单易学、双向数据绑定、组件化、...
    99+
    2024-04-02
  • laravel添加角色和模糊搜索功能怎么实现
    这篇“laravel添加角色和模糊搜索功能怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“laravel添加角色和模糊...
    99+
    2023-07-04
  • 使用vue怎么实现身份认证管理和租户管理功能
    本篇文章为大家展示了使用vue怎么实现身份认证管理和租户管理功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。按钮级权限src\utils\abp.js:export function&n...
    99+
    2023-06-15
  • Win10 10102预览版怎么卸载应用程序和添加功能?
    Windows系统中有一些我们不需要用到的应用程序,如何卸载这些不常用的应用程序呢?Windows10 10102版系统卸载应用程序与其它系统又不相同,我们应该如何卸载呢? 1、我们左键点击:开始,在应用中点击:设置; ...
    99+
    2023-06-15
    Win10 10102 预览版 预览 添加 应用程序
  • 怎么用WordPress给文章添加百度是否已收录查询和显示功能
    这篇文章主要介绍“怎么用WordPress给文章添加百度是否已收录查询和显示功能”,在日常操作中,相信很多人在怎么用WordPress给文章添加百度是否已收录查询和显示功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对...
    99+
    2023-06-10
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作