Spring Boot学习篇(十)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

Spring Boot学习篇(十)

shiro安全框架使用篇(二)——登录实例(密码以密文方式存储,不含记住密码)

1.模拟注册时,生成密文到数据库中

1.1 在zlz包下创建util包,并在下面创建SHAUtil01类(初始里面无方法)和SHAUtil02类,其目录结构如下所示

在这里插入图片描述

1.2 两种生成密文的方式

1.2.1 自己指定盐
a 核心代码
 public static String shaPassword(String oldPwd,String salt){
        return new SimpleHash("sha-256",oldPwd,salt,100).toString();
}
b 完整代码
package com.zlz.util;
import org.apache.shiro.crypto.hash.SimpleHash;
import java.util.Random;
public class SHAUtil01 {
    /**
     * 对密码使用sha256算法的方式加密
     * 加密不可逆: 无法通过新生成密文来反推出原来的密码
     * 盐是为了提高密码的安全系数的 随机生成的
     * 实际是拿你随机生成的盐和原来的字符串拼接在一起在来生成密文
     * 一般是可以使用随机字符串来表示盐的
     * hashIteration 表示加密计算的次数(拿盐和字符串拼接的次数) 散列次数越多 安全系越高
     * @param oldPwd 原密码
     * @param salt  盐
     * @return
     */
    public static String shaPassword(String oldPwd,String salt){
        return new SimpleHash("sha-256",oldPwd,salt,100).toString();
    }
    public static void main(String[] args) {
        //想要对admin这个密码进行加密.sha-256是不可逆的加密方式,对同一个密码生成的密文是唯一的,无论你执行多少次
        //注意这个盐是建议每个账户一个,尽量不要重复
        String newPwd = SHAUtil01.shaPassword("admim", "q1");
        System.out.println(newPwd);
    }
}
1.2.2 随机生成盐
a 核心代码
//①定义一个随机生成10位含字母数字符号的盐
static Random random=new Random();
public static String getSalt(){
    //盐从以下这些字符中去随机取出10个出来,下面盐的字符串是可以自定义的,专门弄一个方法拿到盐
    String salts="ewsfjbwdufgsfsnuivhe123456789/*;[]";
    StringBuffer salt=new StringBuffer();
    for (int i = 1; i <=10; i++) {
        //charAt是取出索引处的字符
        char c=salts.charAt(random.nextInt(salts.length()));
        salt.append(String.valueOf(c));
    }
    return salt.toString();
}
//②sha-256的加密方式(不可逆的)进行加密得到密文
public static String shaPassword(String oldPwd){
    return new SimpleHash("sha-256",oldPwd,getsalt(),100).toString();
}
b 完整代码
package com.zlz.util;

import org.apache.shiro.crypto.hash.SimpleHash;

import java.util.Random;

public class SHAUtil02 {
    /**
     * 对密码使用sha-256算法的方式加密
     * 加密不可逆: 无法通过新生成密文来反推出原来的密码
     *
     * 盐是为了提高密码的安全系数的 随机生成的
     * 实际是拿你随机生成的盐和原来的字符串拼接在一起在来生成密文
     * 一般是可以使用随机字符串来表示盐的
     * hashIteration 表示加密计算的次数(拿盐和字符串拼接的次数) 散列次数越多 安全系越高
     * @param oldPwd 原密码
     * @return 字符串形式的密文
     */
    public static String shaPassword(String oldPwd){
        return new SimpleHash("sha-256",oldPwd,getSalt(),100).toString();
    }
    static Random random=new Random();
    public static String getSalt(){
        //盐从以下这些字符中去随机取出10个出来,下面盐的字符串是可以自定义的,专门弄一个方法拿到盐
        String salts="ewsfjbwdufgsfsnuivhe123456789/*;[]";
        StringBuffer salt=new StringBuffer();
        for (int i = 1; i <=10; i++) {
            //charAt是取出索引处的字符
            char c=salts.charAt(random.nextInt(salts.length()));
            salt.append(String.valueOf(c));
        }
        return salt.toString();
    }
    public static void main(String[] args) {
        //想要对admin这个密码进行加密.sha-256是不可逆的加密方式,对同一个密码生成的密文是唯一的,无论你执行多少次
        String newPwd = SHAUtil02.shaPassword("admin");
        System.out.println(newPwd);
    }
}

1.3 手动变更数据表(以自己指定盐的方式)

1.3.1 生成账户"admin"所对应的密文
a 测试代码
public static void main(String[] args) {
    //想要对admin这个密码进行加密.是不可逆的加密方式,对同一个密码生成的密文是唯一的,无论你执行多少次
    String newPwd = SHAUtil01.shaPassword("admin", "q1");
    System.out.println(newPwd);
}
b 运行截图

在这里插入图片描述

1.3.2 账户"aaa"所对应的密文
a 测试代码
public static void main(String[] args) {
    //想要对admin这个密码进行加密.是不可逆的加密方式,对同一个密码生成的密文是唯一的,无论你执行多少次
    String newPwd = SHAUtil01.shaPassword("aaa", "q2");
    System.out.println(newPwd);
}
b 运行截图

在这里插入图片描述

1.3.3 账户"bbb"所对应的密文
a 测试代码
public static void main(String[] args) {
    //想要对admin这个密码进行加密.是不可逆的加密方式,对同一个密码生成的密文是唯一的,无论你执行多少次
    String newPwd = SHAUtil01.shaPassword("bbb", "q3");
    System.out.println(newPwd);
}
b 运行截图

在这里插入图片描述

1.3.4 手动更改sys_user表的salt字段,更改后的效果如下所示

在这里插入图片描述

1.4 sys_user表所对应的sql语句(生成对应密文后的版本)

/*
 Navicat Premium Data Transfer

 Source Server         : localhost_3305
 Source Server Type    : MySQL
 Source Server Version : 80030
 Source Host           : 127.0.0.1:3305
 Source Schema         : db0618

 Target Server Type    : MySQL
 Target Server Version : 80030
 File Encoding         : 65001

 Date: 15/01/2023 22:21:15
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` int NOT NULL,
  `username` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `password` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `salt` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `suo` int NULL DEFAULT 0,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = COMPACT;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, 'admin', '7e84f2fbdc9de493dc1e17c44b163ebc9168bc472f26db231f472f1012e62d87', 'q1', 0);
INSERT INTO `sys_user` VALUES (2, 'aaa', '18ae76b69e6b7b2ae78100013442beafb692bbbad663b1ff5845f0036b446ad7', 'q2', 0);
INSERT INTO `sys_user` VALUES (3, 'bbb', '7c8425aa02dfdfc973257f3b2a4ded786eadee830d7a29a900669727fa7a5966', 'q3', 1);

SET FOREIGN_KEY_CHECKS = 1;

2 在config包下创建域(MysqlRealm类)

package com.zlz.config;

import com.zlz.entity.SysUser;
import com.zlz.mapper.SysUserMapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

public class MysqlRealm extends AuthorizingRealm {
    //授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        return null;
    }
    @Autowired
    SysUserMapper sysUserMapper;
    //认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
        //①在认证方法里面获取输入的用户名
        String username = (String) at.getPrincipal();
        SysUser user = sysUserMapper.findUserByUsername(username);
        if (user == null) {
            //②如果账户不存在,就抛出账户不存在异常
            throw new UnknownAccountException();
        }
        //③检查账户是否锁定 如果锁定的话,那就会抛出锁定异常
        if(user.getSuo()==1){
            throw new LockedAccountException();
        }
        //密码错误,shiro会自动帮你抛出密码错误这个异常的
//        System.out.println("实例对象名称:");
        //④拿到盐(放在第三个形参的位置)-----变动的地方
        ByteSource salt = ByteSource.Util.bytes(user.getSalt());
        //⑤把对应的参数设置进去
        SimpleAuthenticationInfo s=new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),salt,getName());
        return s;
    }
}

3.在config包下创建ShiroConfig类(进行shiro的相关配置)

package com.zlz.config;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConig {
    //安全管理器的配置
    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager dws=new DefaultWebSecurityManager();
        dws.setRealm(mysqlRealm());
        //设置会话管理器,保证第一次访问的时候不会出错
        dws.setSessionManager(new DefaultWebSessionManager());
        return dws;
    }
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean factoryBean(){
        ShiroFilterFactoryBean sffb=new ShiroFilterFactoryBean();
        //设置安全管理器
        sffb.setSecurityManager(securityManager());
        //设置需要登录但没有登录的地址
        sffb.setLoginUrl("");
        //检测到没有权限时的跳转地址
        sffb.setUnauthorizedUrl("");
        return sffb;
    }
    @Bean
    public MysqlRealm mysqlRealm(){
        MysqlRealm mysqlRealm=new MysqlRealm();
        //变动的地方: 配置加密管理器 登录时 会使用该加密方式对输入的密码进行加密,再和数据库的密码进行比对
        HashedCredentialsMatcher hsm = new HashedCredentialsMatcher();
        hsm.setHashAlgorithmName("sha-256");//加密方式 与注册时保持一致
        hsm.setHashIterations(100);//散列次数 与注册时保持一致
        mysqlRealm.setCredentialsMatcher(hsm);
        return mysqlRealm;
    }
}

4 最终测试

4.1 当账户输入有误时

a 点击登录按钮前

在这里插入图片描述

b 点击登录按钮后

在这里插入图片描述

4.2 当账户被锁定时

a 点击登录按钮前

在这里插入图片描述

b 点击登录按钮后

在这里插入图片描述

4.3 当密码输入有误时(该用户并没有被锁定)

a 点击登录按钮前

在这里插入图片描述

b 点击登录按钮后

在这里插入图片描述

4.4 当账户密码输入均正确时

a 点击登录按钮前

在这里插入图片描述

b 点击登录按钮后

在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring