玩一玩基于Token的 自定义身份认证+权限管理

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

 

一,用户点击登录时 对用户名密码进行检查。 当状态为Success   进而通过用户名密码去生成一个身份验证的令牌

从而对令牌进行加密 生成Token  然后放入Cookie里

复制代码
        public ActionResult Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            LoginManager loginManager = new LoginManager();
            var result = loginManager.SignIn(model.Email, model.Password);
            if (result == LoginState.Success)
            {
                var role = loginManager.GetUserRoleByEmailAsync(model.Email);

                //通过用户名(邮箱) 密码生成一个ticket令牌
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, model.Email, DateTime.Now,
                    DateTime.Now.AddMinutes(30), true, string.Format("{0}&{1}", model.Email, model.Password));
                
                //加密
                var Token = FormsAuthentication.Encrypt(ticket);

                System.Web.HttpContext.Current.Session["UserName"]=model.Email;
                System.Web.HttpContext.Current.Session["Role"] = role;

                //将Token加入到cookie  并设置为5天过期
                var cookie = new HttpCookie("Token", Token)
                {
                    Expires = DateTime.Now.AddDays(5)
                };
                Response.Cookies.Add(cookie);

                if (returnUrl != null)
                {
                    return Redirect(returnUrl);
                }
                return Redirect("/Home/Chat");
            }

            return View();
}
复制代码

 

 

二,继承并重写 AuthorizeAttribute 中的 OnAuthorization  

这里 我建了个XML文件用来存放action的角色权限  

用来对方法访问的控制。  这里会解析token 然后进行匹配

复制代码
<?xml version="1.0" encoding="utf-8" ?>
<Roles>
  <Controller name="Home">
    <Action name="Index"></Action>
    <Action name="Chat">Admin,VIP5,VIP4</Action>
  </Controller>
    <Controller name="Account">
    <Action name="Index"></Action>
    <Action name="GETint">Admin,VIP5,VIP4</Action>
  </Controller>
</Roles>
复制代码

 

复制代码
   public class MVCAuthorize : AuthorizeAttribute
    {
        public new string Roles { get; set; } //这个是从Action中传过来的角色
        public override void OnAuthorization(AuthorizationContext actionContext)
        {

            var token = actionContext.HttpContext.Request.Params["Token"];

            if (!string.IsNullOrEmpty(token))
            {
                string controllerName = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName; //得到控制器名称
                string actionName = actionContext.ActionDescriptor.ActionName;//得到Action名称
                string roles = GetActionRoles(actionName, controllerName); // 在Xml文件中根据控制器 Action 找到对应的访问角色权限
                if (!string.IsNullOrWhiteSpace(roles))
                {
                    this.Roles = Roles + "," + roles;
                    var isAuthValidate = ValidateTicket(token, Roles);
                    if (isAuthValidate != AuthorizeState.ValidateSuucss)
                    {
                        base.HandleUnauthorizedRequest(actionContext);
                    }

                }
            }
else{
             base.HandleUnauthorizedRequest(actionContext);

} } //获取当前Action的访问角色 public static string GetActionRoles(string action, string controller) { XElement rootElement = XElement.Load(HttpContext.Current.Server.MapPath("/") + "/XML/RoleAction.xml"); XElement controllerElement = findElementByAttribute(rootElement, "Controller", controller); if (controllerElement != null) { XElement actionElement = findElementByAttribute(controllerElement, "Action", action); if (actionElement != null) { return actionElement.Value; } } return ""; } public static XElement findElementByAttribute(XElement xElement, string tagName, string attribute) { return xElement.Elements(tagName).FirstOrDefault(x => x.Attribute("name").Value.Equals(attribute, StringComparison.OrdinalIgnoreCase)); } //校验用户名密码(对Session匹配,或数据库数据匹配) private AuthorizeState ValidateTicket(string encryptToken,string role) { if (encryptToken == null) { return AuthorizeState.TokenErro; } //解密Ticket var strTicket = FormsAuthentication.Decrypt(encryptToken).UserData; //从Ticket里面获取用户名和密码 var index = strTicket.IndexOf("&"); string userName = strTicket.Substring(0, index); string password = strTicket.Substring(index + 1); ArrayList arrayList = new ArrayList(role.Split(',')); var roleName = HttpContext.Current.Session["Role"].ToString(); var name = HttpContext.Current.Session["UserName"].ToString(); //取得session,不通过说明用户退出,或者session已经过期 if name!=username, 说明过期或者用户退出了 if (arrayList.Contains(roleName) && name == userName) //获取对应控制器 对应方法的访问角色权限 如果包含说明符合访问 否则返回权限错误 { return AuthorizeState.ValidateSuucss; } else { return AuthorizeState.UserValidateErro; } } }
复制代码

 

当我们去访问这个方法时。他会先进行身份验证。进入MVCAuthorize中。 这里你可以扩展开来。 比如我临时需要对这个方法在多开放些角色 ,可以直接在action 带上

复制代码
        [MVCAuthorize(Roles = "VIP9,ActiveUser")]
        public ActionResult Chat()
        {

            var account = HttpContext.User.Identity.Name;
            ModelDBContext db = new ModelDBContext();
            //ViewBag.UserName =db.User.Where(x=>x.Email == account).FirstOrDefault().FullName;         
            return View();
        }
复制代码

 

当检测到用户未登陆 。 没有通过认证的同时 去访问的话。  会返回一个401 你没有当前页面权限访问

 

然后就是通过验证后的样子

常常是看别人怎么实现。 还是自己多去实践 才能成长更快。 加油

工作之余。手撸代码。颇有漏洞。望君批正。

 

https://www.cnblogs.com/zixuan9527/p/8601151.html

转载于:https://www.cnblogs.com/sjqq/p/9111121.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 基于 Spring Security 实现自定义 token 登录的步骤如下: 1. 实现自定义 Token 类,继承 org.springframework.security.authentication.UsernamePasswordAuthenticationToken。 2. 实现自定义 AuthenticationProvider,继承 org.springframework.security.authentication.AuthenticationProvider,在 authenticate 方法中校验 token 的有效性。 3. 在 Spring Security 配置类中添加自定义 AuthenticationProvider。 4. 在控制器中,在用户登录时,生成自定义 token 并存储到客户端。 5. 在接口请求中,在请求头中携带 token,Spring Security 会自动校验 token 的有效性。 ### 回答2: 基于 Spring Security 实现自定义 token 登录的方法如下: 1. 创建自定义Token 类:可以通过实现 `AuthenticationToken` 接口来创建自定义Token 类,该接口定义了 getPrincipal 和 getCredentials 方法用于获取身份和凭证信息。 2. 创建自定义的 AuthenticationProvider 类:可以通过继承 `AbstractUserDetailsAuthenticationProvider` 类来创建自定义的 AuthenticationProvider 类,在该类中重写 authenticate 方法来实现自定义的认证逻辑。在 authenticate 方法中,首先将传入的 Authentication 对象转换为自定义Token 对象,然后进行一系列自定义的验证操作,最后返回一个已认证的 Authentication 对象。 3. 配置 Spring Security :将自定义的 AuthenticationProvider 注册到 Spring Security 的配置文件中,例如通过 `AuthenticationManagerBuilder` 的 `authenticationProvider` 方法将其添加到 AuthenticationManagerBuilder 中。 4. 创建登录接口:创建一个登录接口用于接收用户提供的身份和凭证信息,例如使用 POST 请求传递用户名和密码。在该接口中,可以使用 `AuthenticationManager` 对象的 `authenticate` 方法来进行认证。 5. 生成 Token :在认证成功后,可以根据用户信息生成一个自定义Token 并返回给用户。可以使用 JSON Web Token(JWT) 来生成 Token,并将 Token 存储在缓存或数据库中。 6. 创建 Token 校验过滤器:创建一个自定义的过滤器用于校验用户请求中的 Token 是否有效。在该过滤器中,可以使用 JWT 来解析 Token,并验证 Token 的合法性。 7. 配置 Token 校验过滤器:将自定义Token 校验过滤器配置到 Spring Security 的过滤器链中,以确保每个请求都会进行 Token 的校验。 通过以上步骤,就可以实现基于 Spring Security 的自定义 Token 登录功能。用户在登录时,提供身份和凭证信息,经过认证后返回一个自定义Token,用户在后续的请求中携带该 Token 来进行身份验证。 ### 回答3: 基于 Spring Security 实现自定义 Token 登录可以通过以下步骤完成: 1. 创建一个自定义Token 类,该类可以包含用户的认证信息和其他必要的信息。 2. 继承 Spring Security 中的 AbstractAuthenticationToken 类来实现自定义 Token 类。重写构造方法和其他必要的方法。 3. 创建一个自定义Token 过滤器,在该过滤器中解析请求中的 Token,并将其转换成自定义 Token 类的实例。 4. 创建一个自定义的 AuthenticationProvider 类,用于验证 Token 的有效性。在 authenticate() 方法中,通过调用用户认证的逻辑来验证 Token,并将验证结果返回。 5. 配置 Spring Security,将自定义Token 过滤器和 AuthenticationProvider 注册到 Spring Security 的过滤器链上。 6. 根据业务需求,可以选择将 Token 存储在数据库、缓存中或者使用其他持久化方式。 7. 在登录接口中生成 Token 并返回给客户端。客户端在后续的请求中携带 Token 来进行访问控制操作。 8. 在需要进行访问控制的接口中,使用 Spring Security 的注解来进行权限验证,例如 @PreAuthorize、@PostAuthorize 等。 通过以上步骤,我们可以基于 Spring Security 实现自定义 Token 登录。这种方式能够灵活地满足不同场景下的用户登录需求,并提供高度可定制化的权限管理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值