asp.net mvc 登录页面使用Token

近来在研究一个单点登录的例子 , 以下是一些笔记,写错的地方请见谅。

Token【登录凭证】
网络身份验证 ,常常需要输入账号和密码,  在第一次登录成功之后,会生成一个Token字符串用于记录登录成功的信息, 这个Token可以在一定时间范围内用于证明自己曾经登录成功。当这段时间范围过期之后Token会失效。
 Token可以翻译为令牌,我觉得译为“登录凭证”更加贴切。(古代锦衣卫获得皇帝的颁发之后,拿着这个牌子就可以到处走,不需要再次身份验证!现代时尚一点的解释就是,家里的汽车安装了高速公路ETC之后,路路通,无需在高速公路出口排队交钱)


JWT【全称 Json Web Token】
这是实现Token字符的一种规范格式,这个格式由A.B.C三部分组成,大概如下,
A部分:是头部header , 里面是一些加密方式,字符长度的内容;
B部分:是载荷Payload , 里面是过期时间,用户信息等内容
c部分:是加密签名Signature 

 

这个图片想要实现的功能是: 多个网页系统都由一个统一的登陆入口进入 , 登录成功之后 ,不同系统之间无需重复输入密码验证。

比分说: 我打开BPM网页登陆之后 ,然后切换到ERP系统,无需重新输入一次密码,可以之间打开我的ERP账号。

 

首先制作一个叫sso 的asp.net mvc 站点 , 里面最重要的就是 Login 页面 , controller和 html如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SSOTest2.DataAccess;
using ClassLibraryToken;
using SSOTest2.Models;

namespace SSOTest2.Controllers
{
    public class LogInController : Controller
    {
        //登录页面
        public ActionResult Index()
        {
            string sysCode = Request.Params["syscode"];
            ViewBag.sysCode = sysCode;
            return View();
        }

        //登录按钮
        public ActionResult Sign(string account, string password)
        {
            UserLoginDAL dal = new UserLoginDAL();
            if (dal.CheckPwd(account, password) == true)
            {
                string tokenVAL = TokenHelper.EncodingToken();

                HttpCookie cookie = new HttpCookie("ssologin", tokenVAL);
                HttpContext.Response.Cookies.Add(cookie);
                //去到首页(syscode对应的页面)
                var wheresys = SystemListInfo.AllConfig().Where(x => x.SystemCode.ToUpper() == Request.Form["sc"].ToUpper()).FirstOrDefault();

                return Redirect(wheresys.SystemHomePage);
            }
            else
            {
                //不通过,回到登录界面
                return Content("账号密码错误");
            }
        }

    }





}

 

 


@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div> 
        <form action="/login/sign" method="post">
            <p>
                用户名:
                <input type="text" id="account" name="account" />
            </p>
            <p>
                密码:
                <input type="text" id="password" name="password" />
            </p>
            <p>
                system:
                <input type="text" value="@Html.Raw(ViewBag.sysCode)" id="sc" name="sc" />
            </p>
            <input type="submit" value="登录" />
        </form>
    </div>
</body>
</html>

可以看到Controller 里面有TokenHelp的帮助类 , 这个类就是用于  创建或者解释  Token(JWT)字符串的类,代码如下:

首先你要使用Nuget工具获取JWT的类库 , 如图

然后编写TokenHelp代码 ,值得一提的是, EncodingToken是把明文信息加密成A.B.C三部分加密信息。 DecodingToken 就是把A.B.C 解码成原始的信息。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using JWT;
using JWT.Algorithms;
using JWT.Serializers;


namespace ClassLibraryToken
{
    public class TokenHelper
    {
        //自定义密钥
        private const string SecretKey = "abcd1234";

        //Token 加密
        public static string EncodingToken()
        {
            string tokenSTR = "";

            try
            {
                TokenInfo tokenInfo = new TokenInfo();

                Dictionary<string, object> payload = new Dictionary<string, object>();
                payload.Add("aud", tokenInfo.aud);
                payload.Add("exp", tokenInfo.exp);
                payload.Add("iat", tokenInfo.iat);
                payload.Add("iss", tokenInfo.iss);
                payload.Add("jti", tokenInfo.jti);
                payload.Add("sub", tokenInfo.sub);

                IJwtAlgorithm algorithm = new HMACSHA256Algorithm();   // symmetric
                IJsonSerializer serializer = new JsonNetSerializer();
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);

                tokenSTR = encoder.Encode(payload, SecretKey);
                Console.WriteLine(tokenSTR);
            }
            catch (Exception ex)
            {
                //Console.WriteLine(ex.Message);
                ClassLibraryLog.LogHelp.Error(ex.Message);
            }
            return tokenSTR;
        }

        //Token 解密
        public static string DecodingToken(string token)
        {
            string tokenJson = "";

            try
            {
                IJsonSerializer serializer = new JsonNetSerializer();
                var provider = new UtcDateTimeProvider();
                IJwtValidator validator = new JwtValidator(serializer, provider);
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric
                IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);

                tokenJson = decoder.Decode(token, SecretKey, verify: true);
            }
            catch (Exception ex)
            {
                //Console.WriteLine(ex.Message);
                ClassLibraryLog.LogHelp.Error(ex.Message);
            }
            return tokenJson;
        }

    }




public class TokenInfo
    {
        /*
        iss:发行人  "iss":"xxxxx"
        iat:发布时间   "iat": 1535967430,
        exp:到期时间  "exp": 1535974630, 
        sub:面向的用户 "sub": "www.xxx.com",
        aud:用户  "aud":"xxxx"
        nbf:在此之前不可用  "nbf": 1535967430,  
        jti:唯一标记    "jti": "9f10e796726e332cec401c569969e13e" 
        除以上默认字段外,我们还可以自定义私有字段,例如 UserInfo
        */

        /// <summary>
        /// 签发者
        /// </summary>
        public string iss { get; set; }

        /// <summary>
        /// 当前时间戳 
        /// </summary>
        public double iat { get; set; }

        /// <summary>
        /// 过期时间戳
        /// </summary>
        public double exp { get; set; }

        /// <summary>
        /// 接收方 
        /// </summary>
        public string aud { get; set; }

        /// <summary>
        /// 面向的用户 
        /// </summary>
        public string sub { get; set; }

        /// <summary>
        /// 唯一标识 
        /// </summary>
        public string jti { get; set; }

        public TokenInfo()
        {
            iss = "颁发者非必填";
            aud = "接收方非必填";
            sub = "面向的用户,一般是某个角色的管理员";

            iat = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
            exp = iat + 120;  //截至+120秒
            jti = Guid.NewGuid().ToString();
        }
    }





}

等用户填写 userID 和 password 正确之后 ,  浏览器会在cookie 里面记录一个 Token

HttpCookie cookie = new HttpCookie("ssologin", tokenVAL);

 

其他系统的home page url 进入的时候 ,先查看是否存在这个cookie ,

如果有的话 ,就正常进入 ;   没有的话,就跳转到login页面

其他系统的syscode和home page 可以写在一个config文件里面 ,我这里就简单演示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SSOTest2.Models
{

    /// <summary>
    /// 系统配置表
    /// </summary>
    public class ExternalSysConf
    {
        /// <summary>
        /// 系统编号
        /// </summary>
        public string SystemCode { get; set; }

        /// <summary>
        /// 系统密钥
        /// </summary>
        public string SecretKey { get; set; }

        /// <summary>
        /// 系统首页地址
        /// </summary>
        public string SystemHomePage { get; set; }
    }


    /// <summary>
    /// 系统详细配置(其实这个应该写在config里面,我就省略了)
    /// </summary>
    public class SystemListInfo
    {
        public static List<ExternalSysConf> AllConfig()
        {
            List<ExternalSysConf> conf = new List<ExternalSysConf>();
            conf.Add(new ExternalSysConf { SecretKey = "aasdasdw", SystemCode = "ERP", SystemHomePage = "http://localhost:62494/home" });
            conf.Add(new ExternalSysConf { SecretKey = "gfdfgdfg", SystemCode = "BPM", SystemHomePage = "http://localhost:59259/home?hello" });
            conf.Add(new ExternalSysConf { SecretKey = "cvcvdfew", SystemCode = "MAA", SystemHomePage = "http://192.168.62.2/home/index" });
            conf.Add(new ExternalSysConf { SecretKey = "34321212", SystemCode = "TYS", SystemHomePage = "http://192.168.34.6/home/index" });
            conf.Add(new ExternalSysConf { SecretKey = "yt445frg", SystemCode = "TTS", SystemHomePage = "http://192.168.98.5/home/index" });
            //这些配置可以写在XML文件里面,我这里只是演示
            return conf;
        }
    }





}

写道这里,sso部分已经做好了 。 

然后再来看ERP的一些页面 , 比如ERP的homeController是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;


namespace ERP.Controllers
{
    public class HomeController : Controller
    {
        // ERP: Home
        public ActionResult Index()
        {

            HttpCookie ssoCookie = Request.Cookies.Get("ssologin");
            if (ssoCookie != null)
            {
                string jwt = ssoCookie.Value;
                ClassLibraryLog.LogHelp.Info("ERP Home Index:" + jwt);

                string kai = ClassLibraryToken.TokenHelper.DecodingToken(jwt);
                ClassLibraryLog.LogHelp.Info("jiekai:" + kai);

                if (string.IsNullOrEmpty(kai) == true)
                {
                    return Redirect("http://localhost:60683/login/index?syscode=erp");
                }
            }
            else
            {
                ClassLibraryLog.LogHelp.Warn("no ssoLogin cookie");
                return Redirect("http://localhost:60683/login/index?syscode=erp");
            }

            return View();
        }

    }
















}

可以看到在进入index方法之后 ,首先是判断 cookie是否存在 , 然后再处理其他事情。

如何每一个action 都是这么写的话,显然是很累赘的,这时候就可以使用到MVC里面的过滤器。 

下面我在BPM网站里面做一个授权过滤器的例子:

先看BPM 的HomeController 代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BPM.Filters;

namespace BPM.Controllers
{
    public class HomeController : Controller
    {
        // BPM: Home
        [MyAuthorizationFilter]
        public ActionResult Index()
        {
            return View();
        }

    }








}

可以发现 代码里面只有一行[MyAuthorzationFilter] 来检查cookie , 没有了erp网站的累赘代码 , 过滤器的代码实现如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace BPM.Filters
{
    public class MyAuthorizationFilter : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            bool checkFlag = false;

            try
            {
                HttpCookie ssoCookie = httpContext.Request.Cookies.Get("ssologin");
                if (ssoCookie != null)
                {
                    string jwt = ClassLibraryToken.TokenHelper.DecodingToken(ssoCookie.Value);
                    //ClassLibraryLog.LogHelp.Info(jwt);

                    if (string.IsNullOrEmpty(jwt) == false)
                    {
                        checkFlag = true;
                    }
                    else {
                        checkFlag = false;
                    }
                }
                else {
                    checkFlag = false;
                    ClassLibraryLog.LogHelp.Warn("BPM-filter find no ssoLogin token");
                }

            }
            catch (Exception ex)
            {
                //Console.WriteLine(ex.Message);
                ClassLibraryLog.LogHelp.Error(ex.Message);
            }

            //return base.AuthorizeCore(httpContext);
            return checkFlag;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            //登陆页的url应该写在config里面 
            filterContext.HttpContext.Response.Redirect("http://localhost:60683/login/index?syscode=bpm");
            base.HandleUnauthorizedRequest(filterContext);
        }


    }









}

过滤器里面可以通过override来重新方法 , 在visual studio 里面编辑的时候 ,只要敲override,然后按一下空格键,就能看到具体的信息。

 

写的这里, Token的实现和过滤器的使用,就写完了 ,希望大家能看懂。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
ASP.NET MVC 中实现 JWT 认证需要以下步骤: 1. 安装 `Microsoft.AspNetCore.Authentication.JwtBearer` 包 可以通过 NuGet 包管理器或者命令行安装该包。 2. 在 `Startup.cs` 文件中添加认证服务 在 `ConfigureServices` 方法中添加如下代码: ```csharp services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "your_issuer", ValidAudience = "your_audience", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_secret_key")) }; }); ``` 其中,`your_issuer` 和 `your_audience` 分别代表你的应用程序的发行者和接收者,`your_secret_key` 是用于签名和验证 JWT 的密钥。 3. 在 `Configure` 方法中启用认证服务 在 `Configure` 方法中添加如下代码: ```csharp app.UseAuthentication(); ``` 4. 在控制器中添加 `[Authorize]` 属性 在需要进行认证的控制器或者方法上添加 `[Authorize]` 属性即可。 5. 在登录时生成 JWT 并将其返回给客户端 在登录验证成功后,生成 JWT 并将其返回给客户端。可以使用 `System.IdentityModel.Tokens.Jwt` 包来生成 JWT,示例代码如下: ```csharp var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.UTF8.GetBytes("your_secret_key"); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, "your_username"), new Claim(ClaimTypes.Role, "your_role") }), Expires = DateTime.UtcNow.AddDays(7), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); var jwt = tokenHandler.WriteToken(token); ``` 其中,`your_username` 和 `your_role` 分别代表该用户的用户名和角色。 以上就是在 ASP.NET MVC 中实现 JWT 认证的基本步骤。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值