• .NET、VUE利用RSA加密完成登录并且发放JWT令牌设置权限访问


    后端生成公钥私钥

    使用RSA.ToXmlString(Boolean) 方法生成公钥以及私钥。

    1. RSACryptoServiceProvider rSA = new();
    2. string pubKey = rSA.ToXmlString(false);//公钥
    3. string priKey = rSA.ToXmlString(true);//私钥

    后端将生成的公钥发送给前端 

    创建一个get请求,将后端生成的公钥发送给前端,需要注意,这里生成的公钥是XML格式需要转换为pkcs8格式,前端JS只能处理pkcs8格式,私钥不能发给前端!!!!

    这里需要安装一个包XC.RSAUtil用于转换格式。

    Install-Package XC.RSAUtil -Version 1.3.6

    1. [HttpGet]
    2. public object Edd()
    3. {
    4. var keyList = RsaKeyConvert.PublicKeyXmlToPem(pubKey);//将xml格式转换为Pkcs8
    5. return keyList;
    6. }

    前端使用公钥加密密码 

     使用的加密库为JSEncrypt库,安装JSEncrypt库。

    npm install jsencrypt -D

    页面引用 

    import {JSEncrypt} from 'jsencrypt'

     界面

    1. "JWT">
    2. <div>
    3. 账号:<input type="text" v-model="MyName"/>
    4. div>
    5. <div>
    6. 密码:<input type="text" v-model="MyPassword"/>
    7. div>
    8. <button @click="Myinput">登录button>
  •  保存账号密码以及后端发送过来的公钥。

    1. data() {
    2. return {
    3. MyName: null,//账号
    4. MyPassword: null,//密码
    5. pubKey:null//公钥
    6. JWTkey:null//JWT令牌
    7. }
    8. }

     在使用登录界面时调用函数接收公钥并且保存。

    1. created() {
    2. PostJwtEdd().then(res=>{
    3. this.pubKey=res
    4. }).catch(err => {
    5. console.log(err)
    6. })
    7. }

     前端在输入账号密码后,对密码进行加密,将加密后的密码发送请求给后端,对比成功后前端将JWT令牌保存。

    1. methods:{
    2. Myinput(){
    3. var encryptor = new JSEncrypt()
    4. encryptor.setPublicKey(this.pubKey)
    5. var rsaPassWord = encryptor.encrypt(this.MyPassword)//加密密码
    6. PostJwtDdd(this.MyName, rsaPassWord).then(res => {
    7. this.JWTkey=res//将后端生成的JWT令牌保存
    8. }).catch(err => {
    9. console.log(err)
    10. })
    11. }
    12. }

    发送密码的axio请求部分

    1. export function PostJwtDdd(MyName,MyPassword){
    2. return request({
    3. method: 'post',
    4. url: '/JWTS/Ddd',
    5. data:{
    6. MyName,
    7. MyPassword
    8. }
    9. })
    10. }

     这是发送的账号以及密码密文。

    32d927f2022941459cf1df93cfaf9763.png

     后端接收参数对比

     后端接收得到参数,将密码密文进行解密。

    创建一个类用于接收账号和加密后的密文。

    1. public class RsaKey
    2. {
    3. public string MyName { get; set; }
    4. public string MyPassword { get; set; }
    5. }

     接收参数开始解密对比账号密码。

    1. [HttpPost]
    2. public object Ddd([FromBody] RsaKey rsaKey)
    3. {
    4. rsa.FromXmlString(priKey);//传入私钥进行解密
    5. byte[] cipherbytex;
    6. cipherbytex = rsa.Decrypt(Convert.FromBase64String(rsaKey.MyPassword), false);
    7. var c = Encoding.UTF8.GetString(cipherbytex);//转换为string类型
    8. MyDbContext md = new MyDbContext();//对数据库表创建实体类
    9. var user = md.MyIntroductions.Where(x => x.MyName == rsaKey.MyName).Select(x => x.MyPassword);//数据库中寻找该账号对应的密码
    10. string users = null;
    11. foreach (var v in user)
    12. {
    13. users = v;
    14. }
    15. if (user == null)
    16. {
    17. return new { err = "账号错误" };
    18. }
    19. else
    20. {
    21. if (users == c)
    22. {
    23. //登录成功
    24. }
    25. else
    26. {
    27. return new { err = "密码错误" };
    28. }
    29. }
    30. }

     生成JWT令牌

    登录成功之后开始生成JWT令牌并且返回给前端,在登录成功哪里生成。

    需要安装两个包。

    包1:System.IdentityModel.Tokens.Jwt

    Install-Package System.IdentityModel.Tokens.Jwt

    包2:Microsoft.AspNetCore.Authentication.JwtBearer

    Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

    1. List claims = new List();
    2. claims.Add(new Claim("MyName", rsaKey.MyName));
    3. claims.Add(new Claim(ClaimTypes.Role, rsaKey.MyName));//颁发管理员角色
    4. string key = jwtSettingsOpt.Value.SecKey;
    5. DateTime expire = DateTime.Now.AddSeconds(jwtSettingsOpt.Value.ExpireSeconds);
    6. byte[] secBytes = Encoding.UTF8.GetBytes(key);
    7. var seckey = new SymmetricSecurityKey(secBytes);
    8. var credentials = new SigningCredentials(seckey, SecurityAlgorithms.HmacSha256Signature);
    9. var tokenDescriptor = new JwtSecurityToken(claims: claims, expires: expire, signingCredentials: credentials);
    10. string jwt = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
    11. return jwt;

    这是前端接收到的JWT令牌

    c607913874a0466f9c2926d03d6cefa1.png

     后端权限访问

     后端创建一个post请求,该请求带有[Authorize]

    [Authorize]是一个用于处理权限的,在这里的作用就是对没有JWT令牌的请求返回401错误,也就是我们可以利用这一点来对登录的用户开放一些权限,如果没有JWT令牌那么就无法请求到数据。

    该post请求会返回请求人的账号。

    1. [Authorize]
    2. [HttpPost]
    3. public object Bdd()
    4. {
    5. return this.User.FindFirst("MyName")!.Value;
    6. }

     前端带JWT令牌进行访问

    需要注意的是JWT令牌是通过'Authorization'的一个请求头发送过去,格式必须为:

    Authorization:Bearer+一个空格+后端生成的JWT令牌

    前端界面

    1. MyJwt(){
    2. var JwtKey='Bearer '+this.JWTkey
    3. console.log(JwtKey)
    4. PostJwtBdd(JwtKey).then(res=>{
    5. console.log(res)
    6. }).catch(err=>{
    7. console.log(err)
    8. })
    9. }

    axios请求部分

    1. export function PostJwtBdd(JwtKey){
    2. return request({
    3. method: 'post',
    4. url: '/JWTS/Cdd',
    5. headers: {
    6. 'Authorization': JwtKey
    7. }
    8. })
    9. }

    在后端请求中配置了[Authorize(Roles ="admin")]后,只有在Roles指定的用户才能对其接口进行访问,一般可以用于对管理员的访问,在生成JWT令牌的时候,

    通过claims.Add(new Claim(ClaimTypes.Role, '用户'));来进行匹配,管理员用户。

     该post请求只有用户为admin的才能请求

    1. [Authorize(Roles ="admin")]//配置只有管理员角色才能请求
    2. [HttpPost]
    3. public object Cdd()
    4. {
    5. return this.User.FindFirst("MyName")!.Value;
    6. }

     前端界面

    1. OneJwt(){
    2. var JwtKey='Bearer '+this.JWTkey
    3. console.log(JwtKey)
    4. PostJwtCdd(JwtKey).then(res=>{
    5. console.log(res)
    6. }).catch(err=>{
    7. console.log(err)
    8. })
    9. }

    axios请求部分,同样请求也只能通过'Authorization': 请求头进行发送。

    Authorization+"空格"+生成的JWT令牌

    1. export function PostJwtCdd(JwtKey){
    2. return request({
    3. method: 'post',
    4. url: '/JWTS/Cdd',
    5. headers: {
    6. 'Authorization': JwtKey
    7. }
    8. })
    9. }

    如果带有的是错误的JWT令牌,那么后端会返回401错误,如图所示:

    f781a71d731a47c58f9fd4bd7e4e36ac.png

    并且不会返回任何的对象。

    2b36c695fc414624b4cb1487b33596bb.png

  • 相关阅读:
    NSS [HNCTF 2022 WEEK2]easy_sql
    pytorch数据处理工具箱
    Tomcat和Servlet
    NLP之基于Seq2Seq的单词翻译
    【进程VS容器VS虚拟机】
    如何在页面中制作悬浮发布按钮弹窗
    智慧城市的应用挑战,昇腾AI给出了新解法
    质量问题不是不爆,时候未到
    注解、自定义注解、处理自定义注解
    19.12 Boost Asio 获取远程进程
  • 原文地址:https://blog.csdn.net/qq_58159494/article/details/134033812