C# 开发单点登录(SSO,Single Sign-On)

开发单点登录(SSO,Single Sign-On)系统是一个复杂但非常有用的任务,它允许用户在多个应用程序之间使用同一个登录凭证。下面是一个基本的指南,介绍如何开发一个简单的 SSO 系统。我们将涉及一些关键概念和技术实现,但由于 SSO 系统的复杂性,实际实现可能需要根据具体的需求和环境进行调整。

关键概念

  1. 认证服务器:负责验证用户身份,并发放认证令牌(token)。
  2. 服务提供者:需要保护的应用程序,依赖认证服务器进行用户认证。
  3. 认证令牌:可以是 JWT(JSON Web Token),用来携带用户信息和认证状态。

技术选型

  • 后端技术:C# 和 ASP.NET Core
  • 身份验证协议:OAuth 2.0 或 OpenID Connect
  • 令牌类型:JWT

基本流程

  1. 用户访问服务提供者:用户访问某个应用程序(服务提供者)。
  2. 重定向到认证服务器:服务提供者将用户重定向到认证服务器进行登录。
  3. 用户登录:用户在认证服务器上输入凭证进行登录。
  4. 认证服务器发放令牌:认证成功后,认证服务器发放一个 JWT,并将用户重定向回服务提供者,同时附带令牌。
  5. 服务提供者验证令牌:服务提供者验证令牌的有效性,并获取用户信息。

示例代码

以下是一个简单的示例,展示了如何使用 ASP.NET Core 创建一个认证服务器和服务提供者。

1. 创建认证服务器

首先,创建一个 ASP.NET Core Web API 项目作为认证服务器。

dotnet new webapi -n AuthServer

Startup.cs

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using System.Text;

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();

        var key = Encoding.ASCII.GetBytes("your_secret_key_here");
        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

AuthController.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

[ApiController
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly IConfiguration _configuration;

    public AuthController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpPost("login")]
    public IActionResult Login([FromBody] LoginModel loginModel)
    {
        // Verify user credentials (this is just an example, you should use a real user service)
        if (loginModel.Username == "test" && loginModel.Password == "password")
        {
            var token = GenerateJwtToken(loginModel.Username);
            return Ok(new { token });
        }

        return Unauthorized();
    }

    private string GenerateJwtToken(string username)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.Name, username)
            }),
            Expires = DateTime.UtcNow.AddHours(1),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }
}

public class LoginModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

2. 创建服务提供者

创建一个新的 ASP.NET Core Web 应用程序作为服务提供者。

dotnet new mvc -n ServiceProvider

Startup.cs

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using System.Text;

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();

        var key = Encoding.ASCII.GetBytes("your_secret_key_here");
        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

HomeController.cs

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

public class HomeController : Controller
{
    [Authorize]
    public IActionResult Index()
    {
        return View();
    }

    [AllowAnonymous]
    public IActionResult Login()
    {
        return View();
    }

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Login(LoginModel loginModel)
    {
        var client = new HttpClient();
        var response = await client.PostAsJsonAsync("https://localhost:5001/api/auth/login", loginModel);
        if (response.IsSuccessStatusCode)
        {
            var result = await response.Content.ReadFromJsonAsync<LoginResult>();
            Response.Cookies.Append("JwtToken", result.Token, new CookieOptions { HttpOnly = true });
            return RedirectToAction("Index");
        }

        ModelState.AddModelError("", "Invalid login attempt");
        return View();
    }
}

public class LoginModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

public class LoginResult
{
    public string Token { get; set; }
}

Views/Home/Login.cshtml

@model LoginModel

<form asp-action="Login" method="post">
    <div class="form-group">
        <label asp-for="Username"></label>
        <input asp-for="Username" class="form-control" />
    </div>
    <div class="form-group">
        <label asp-for="Password"></label>
        <input asp-for="Password" type="password" class="form-control" />
    </div>
    <button type="submit" class="btn btn-primary">Login</button>
</form>

3. 配置和运行

认证服务器配置

appsettings.json 中添加 JWT 配置:

"Jwt": {
  "Key": "your_secret_key_here"
}
服务提供者配置

appsettings.json 中添加 JWT 配置:

"Jwt": {
  "Key": "your_secret_key_here"
}

运行项目

  1. 启动认证服务器项目。
  2. 启动服务提供者项目。

访问服务提供者项目的 /Home/Login 页面,输入用户名和密码进行登录。在成功登录后,会将用户重定向到首页,并显示受保护内容。

结论

上述示例展示了如何使用 ASP.NET Core 创建一个简单的 SSO 系统,其中包括一个认证服务器和一个服务提供者。认证服务器负责验证用户并发放 JWT 令牌,服务提供者验证 JWT 令牌并保护受限资源。

请注意,这是一个基本示例,实际应用中需要考虑更多的安全性和功能需求,例如:

  • 更安全的存储和处理密钥。
  • 使用 HTTPS 确保数据传输安全。
  • 添加刷新令牌机制。
  • 更复杂的用户验证和授权逻辑。
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值