代码之家  ›  专栏  ›  技术社区  ›  Ahmer Ali Ahsan

IdentityServer4使用ASP.NET核心中的密码授予请求JWT/访问承载令牌

  •  1
  • Ahmer Ali Ahsan  · 技术社区  · 6 年前

    我使用ASP.NET核心中的IdentityServer4授予密码来请求JWT/access bearer令牌,但我似乎找不到正确的方法来完成它。

    下面是我从中注册用户的Post请求。

    http://localhost:52718/account/register

    下面是使用IdentityServer4获取JWT令牌的不记名令牌获取请求

    http://localhost:52718/connect/token

    下面是我从中登录我的用户的post请求

    http://localhost:52718/account/signin

    现在,我要做的是,当我登录我的用户时,我想要一个JWT/承载令牌,就像我从这里得到的一样 http://localhost:52718/connect/token 。当我点击这个网址时。

    这是我的账户管理员代码:

    使用system.threading.tasks; 使用microsoft.aspnetcore.identity; 使用Microsoft.aspnetcore.mvc; 使用server.models; 使用server.models.accountViewModels; 使用server.models.userviewmodels; 命名空间服务器。控制器 { 公营会计主管:主管 { private readonly用户管理器<applicationuser>usermanager; 专用只读角色管理器<IdentityRole>_RoleManager; 公共会计主管( 用户管理器<应用程序用户>用户管理器, 角色管理器<IdentityRole>角色管理器 ) { _ usermanager=usermanager; _ rolemanager=角色管理器; } [httppost]按钮 公共异步任务<IActionResult>注册([FromBody]RegisterViewModel模型) { 如果(!模型状态.isvalid) { 返回BADREQUEST(ModelState); } var user=new applicationuser username=model.username,firstname=model.firstname,lastname=model.lastname,email=model.email var result=await _usermanager.createasync(用户,模型,密码); string role=“基本用户”; if(result.succeeded) { if(等待rolemanager.findbynameasync(role)==空) { 等待RoleManager.CreateAsync(New IdentityRole(Role)); } 等待_usermanager.addtoroleasync(用户、角色); 等待_usermanager.addclaimasync(user,new system.security.claims.claim(“用户名”,user.username)); 等待_usermanager.addclaimasync(user,new system.security.claims.claim(“firstname”,user.firstname)); 等待_usermanager.addclaimasync(user,new system.security.claims.claim(“lastname”,user.lastname)); 等待_usermanager.addclaimasync(用户、新系统、安全性、声明、声明(“email”,user.email)); 等待_usermanager.addclaimasync(用户、新系统、安全性、声明、声明(“角色”,角色)); 返回OK(new profileviewmodel(user)); } 返回badrequest(result.errors); } 公共异步任务<IActionResult>登录([FromBody]LoginViewModel模型) { 如果(!模型状态.isvalid) { 返回BADREQUEST(ModelState); } var result=await _usermanager.findbynameasync(model.username); 如果(结果!=空&wait UserManager.checkPasswordAsync(result,model.password)) { 返回OK(new profileviewmodel(result)); } 返回badrequest(“用户名或密码无效”); } } }

    当我点击登录方法时,我成功地获得了用户的数据。

    但当用户登录我的应用程序时,我还需要一个JWT/access令牌。

    现在我真正的问题是:

    我可以在登录方法中做些什么,这样当用户登录时,它会返回令牌和其他用户数据。我希望我能简单地解释一下我的问题。

    谢谢

    下面是我注册用户的Post请求。

    http://localhost:52718/account/register

    下面是使用IdentityServer4获取JWT令牌的不记名令牌获取请求

    http://localhost:52718/connect/token

    下面是我从中登录我的用户的post请求

    http://localhost:52718/account/signin

    现在,我想做的是,当我登录我的用户时,我想要一个JWT/承载令牌,就像我从这里得到的一样。http://localhost:52718/connect/token.当我点击这个网址时。

    enter image description here

    这是我的账户管理员代码:

    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.AspNetCore.Mvc;
    using Server.Models;
    using Server.Models.AccountViewModels;
    using Server.Models.UserViewModels;
    
    namespace Server.Controllers
    {
        public class AccountController : Controller
        {
            private readonly UserManager<ApplicationUser> _userManager;
            private readonly RoleManager<IdentityRole> _roleManager;
    
            public AccountController(
                UserManager<ApplicationUser> userManager,
                RoleManager<IdentityRole> roleManager
                )
            {
                _userManager = userManager;
                _roleManager = roleManager;
            }
    
            [HttpPost]
            public async Task<IActionResult> Register([FromBody]RegisterViewModel model)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                var user = new ApplicationUser { UserName = model.UserName, FirstName = model.FirstName, LastName = model.LastName, Email = model.Email };
    
                var result = await _userManager.CreateAsync(user, model.Password);
    
                string role = "Basic User";
    
                if (result.Succeeded)
                {
                    if (await _roleManager.FindByNameAsync(role) == null)
                    {
                        await _roleManager.CreateAsync(new IdentityRole(role));
                    }
                    await _userManager.AddToRoleAsync(user, role);
                    await _userManager.AddClaimAsync(user, new System.Security.Claims.Claim("userName", user.UserName));
                    await _userManager.AddClaimAsync(user, new System.Security.Claims.Claim("firstName", user.FirstName));
                    await _userManager.AddClaimAsync(user, new System.Security.Claims.Claim("lastName", user.LastName));
                    await _userManager.AddClaimAsync(user, new System.Security.Claims.Claim("email", user.Email));
                    await _userManager.AddClaimAsync(user, new System.Security.Claims.Claim("role", role));
    
                    return Ok(new ProfileViewModel(user));
                }
    
                return BadRequest(result.Errors);
    
    
            }
    
            public async Task<IActionResult> Signin([FromBody]LoginViewModel model)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                var result = await _userManager.FindByNameAsync(model.UserName);
    
                if (result != null && await _userManager.CheckPasswordAsync(result, model.Password))
                {
                    return Ok(new ProfileViewModel(result));
                }
    
                return BadRequest("Invalid username or password.");
            }
        }
    }
    

    当我点击登录方法时,我成功地获得了用户的数据。

    enter image description here

    但当用户登录我的应用程序时,我还需要一个JWT/access令牌。

    现在我真正的问题是:

    我可以在登录方法中做些什么,这样当用户登录时,它会返回令牌和其他用户数据。我希望我能简单地解释一下我的问题。

    谢谢

    1 回复  |  直到 6 年前
        1
  •  1
  •   Ahmer Ali Ahsan    6 年前

    我找到了自己的问题答案。在开始之前,我向您展示了我定义客户机的代码。

    public static IEnumerable<client>getclients())
    {
    //客户端凭据客户端
    返回新列表<客户端>
    {
    
    //资源所有者密码授予客户端
    新客户端
    {
    clientid=“ro.angular”,
    allowedgranttypes=granttypes.resourceownerpassword,
    
    客户机密=
    {
    新秘密(“secret”.sha256())
    },请
    允许范围={
    IdentityServerConstants.StandardScopes.OpenID,
    IdentityServerConstants.StandardScopes.Profile,配置文件,
    IdentityServerConstants.StandardScopes.email,
    IdentityServerConstants.StandardScopes.Address,
    “API1”
    }
    }
    }(二)
    }
    

    现在,我在登录方法中所做的就是使用tokenclient类来请求令牌。要创建实例,需要传入令牌端点地址、客户端ID和机密。

    接下来我要使用使用密码grant请求令牌to allows a client to send username and password to the token service and get an access token back that representative that user.

    这是我需要修改的登录代码:

    public async task<iactionresult>登录([frombody]loginviewmodel model)
    {
    var disco=await discovercyclient.getasync(“http://localhost:52718”);
    如果(迪斯科·伊瑟罗)
    {
    返回BAD请求(发现错误);
    }
    
    var tokenclient=新tokenclient(disco.tokenpoint,“ro.angular”,“secret”);
    var tokenresponse=await tokenclient.requestResourceOwnerPasswordAsync(model.username,model.password,“api1 openid”);
    
    if(tokenResponse.isError)
    {
    返回badRequest(tokenResponse.error);
    }
    
    如果(!模型状态.isvalid)
    {
    返回BADREQUEST(ModelState);
    }
    
    var user=_usermanager.findbynameasync(model.username);
    
    var result=await _usermanager.findbynameasync(model.username);
    
    如果(结果!=空&wait UserManager.checkPasswordAsync(result,model.password))
    {
    返回OK(new profileviewmodel(result,tokenResponse));
    }
    
    返回badrequest(“用户名或密码无效”);
    }
    

    另外,我还修改了profileviewModel类,并添加了两个新的标记&expiry:。

    公共类profileviewModel { 公共字符串ID_get;set; 公共字符串firstname_get;set; 公共字符串姓氏get;set; 公共字符串电子邮件get;set; 公共字符串标记get;set; public int expiry_get;set; 公共配置文件视图模型() { } public profileviewmodel(applicationuser用户,tokenResponse utoken=null) { id=user.id; firstname=user.firstname; lastname=user.lastname; email=user.email; token=utoken.accesstoken; expiry=utoken.expiresin; } 公共静态IEnumerable<ProfileViewModel>GetUserProfiles(IEnumerable<ApplicationUser>用户) { var profiles=新列表<profileviewModel> foreach(用户中的applicationuser用户) { profiles.add(new profileviewmodel(user)); } 返回配置文件; } }
    
    

    这是我的欲望输出。希望这个答案能帮助其他人。

    现在,我在登录方法中所做的就是使用tokenclient类来请求令牌。要创建实例,需要传入令牌端点地址、客户端ID和机密。

    接下来我用Requesting a token using the password grant允许客户机向令牌服务发送用户名和密码,并返回代表该用户的访问令牌。

    这是我需要修改的登录代码:

    public async Task<IActionResult> Signin([FromBody]LoginViewModel model)
    {
        var disco = await DiscoveryClient.GetAsync("http://localhost:52718");
        if (disco.IsError)
        {
            return BadRequest(disco.Error);
        }
    
        var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.angular", "secret");
        var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync(model.UserName, model.Password, "api1 openid");
    
        if (tokenResponse.IsError)
        {
            return BadRequest(tokenResponse.Error);
        }
    
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
    
        var user = _userManager.FindByNameAsync(model.UserName);
    
        var result = await _userManager.FindByNameAsync(model.UserName);
    
        if (result != null && await _userManager.CheckPasswordAsync(result, model.Password))
        {
            return Ok(new ProfileViewModel(result, tokenResponse));
        }
    
            return BadRequest("Invalid username or password.");
    }
    

    此外,我还修改profileviewModel类并添加两个新标记&expiry:

    public class ProfileViewModel
    {
        public string Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
    
        public string Token { get; set; }
    
        public int Expiry { get; set; }
    
        public ProfileViewModel()
        {
    
        }
    
        public ProfileViewModel(ApplicationUser user, TokenResponse UToken = null)
        {
            Id = user.Id;
            FirstName = user.FirstName;
            LastName = user.LastName;
            Email = user.Email;
            Token = UToken.AccessToken;
            Expiry = UToken.ExpiresIn;
        }
    
        public static IEnumerable<ProfileViewModel> GetUserProfiles(IEnumerable<ApplicationUser> users)
        {
            var profiles = new List<ProfileViewModel> { };
            foreach (ApplicationUser user in users)
            {
                profiles.Add(new ProfileViewModel(user));
            }
    
            return profiles;
        }
    }
    

    这是我的欲望输出。希望这个答案能帮助别人。

    enter image description here