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 点击登录按钮前
文章来源:https://www.toymoban.com/news/detail-755151.html
b 点击登录按钮后
文章来源地址https://www.toymoban.com/news/detail-755151.html
到了这里,关于Spring Boot学习篇(十)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!