shiro_02_身份认证加密
目录
一、盐加密
1.明文密码
2.md5加密
3.md5加盐加密
4.md5加盐加密加次数 1024
5.演示代码
二、shiro的认证
1.完成登录的方法 层的编写和biz层
2.自定义realm(重点)
3.与shiro的整合(注意)
4.测试
一、盐加密
数据库密码的发展史
第一个阶段:明文密码
第二个阶段:md5加密
第三个阶段:md5加盐加密
第四个阶段:md5加盐加密加次数 1024
1.明文密码
也就是说在数据库里密码是可以看到的
2.md5加密
数据库里的密码已经加密了
也就相当于密码是 =
还可以看下面这张图也就是说这个加密还不够完全,它可以解出来,而且这个加密的密还是同一个,它始终不会变的
3.md5加盐加密
:原始密码
盐:1
盐:2
就是看你的盐加了多少然后就在继续加密
4.md5加盐加密加次数 1024
你要知道加了多少盐,还要知道多少次,也就是说别人加密多少次,你就要解密多少次
5.演示代码
1.导入pom依赖
org.apache.shiro shiro-core 1.3.2
org.apache.shiro shiro-web 1.3.2
org.apache.shiro shiro-spring 1.3.2
所有的pom.xml
4.0.0 org.example ssm 1.0-SNAPSHOT war ssm Maven Webapp http://www.example.com UTF-8 1.8 1.8 3.7.0 5.0.2.RELEASE 3.4.5 5.1.44 5.1.2 1.3.1 2.1.1 2.4.3 2.9.1 4.12 4.0.0 1.18.2 org.springframework spring-context ${spring.version} org.springframework spring-orm ${spring.version} org.springframework spring-tx ${spring.version} org.springframework spring-aspects ${spring.version} org.springframework spring-web ${spring.version} org.springframework spring-test ${spring.version} org.mybatis mybatis ${mybatis.version} mysql mysql-connector-java ${mysql.version} com.github.pagehelper pagehelper ${pagehelper.version} org.mybatis mybatis-spring ${mybatis.spring.version} org.apache.commons commons-dbcp2 ${commons.dbcp2.version} org.apache.commons commons-pool2 ${commons.pool2.version} org.apache.logging.log4j log4j-core ${log4j2.version} org.apache.logging.log4j log4j-api ${log4j2.version} org.apache.logging.log4j log4j-web ${log4j2.version} junit junit ${junit.version} test javax.servlet javax.servlet-api ${servlet.version} provided org.projectlombok lombok ${lombok.version} provided org.springframework spring-webmvc ${spring.version} javax.servlet.jsp javax.servlet.jsp-api 2.3.3 jstl jstl 1.2 taglibs standard 1.1.2 commons-fileupload commons-fileupload 1.3.3 org.hibernate hibernate-validator 6.0.7.Final com.fasterxml.jackson.core jackson-databind 2.9.3 com.fasterxml.jackson.core jackson-core 2.9.3 com.fasterxml.jackson.core jackson-annotations 2.9.3 org.apache.shiro shiro-core 1.3.2 org.apache.shiro shiro-web 1.3.2 org.apache.shiro shiro-spring 1.3.2 ssm src/main/java **/*.xml src/main/resources jdbc.properties *.xml org.apache.maven.plugins maven-compiler-plugin ${maven.compiler.plugin.version} ${maven.compiler.target} ${project.build.sourceEncoding} org.mybatis.generator mybatis-generator-maven-plugin 1.3.2 mysql mysql-connector-java ${mysql.version} true maven-clean-plugin 3.1.0 maven-resources-plugin 3.0.2 maven-compiler-plugin 3.8.0 maven-surefire-plugin 2.22.1 maven-war-plugin 3.2.2 maven-install-plugin 2.5.2 maven-deploy-plugin 2.8.2
2.配置 web.xml 交给进行管理
shiroFilter org.springframework.web.filter.DelegatingFilterProxy targetFilterLifecycle true
shiroFilter /*
所有web.xml
Archetype Created Web Application contextConfigLocation classpath:applicationContext.xml org.springframework.web.context.ContextLoaderListener SpringMVC org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/springmvc-servlet.xml 1 true SpringMVC / encodingFilter org.springframework.web.filter.CharacterEncodingFilter true encoding UTF-8 encodingFilter /* shiroFilter org.springframework.web.filter.DelegatingFilterProxy targetFilterLifecycle true shiroFilter /*
4.在这里新建一个包,里面放.java
package com.jwj.shiro;import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;/*** 用于shiro权限认证的密码工具类*/
public class PasswordHelper {/*** 随机数生成器* 生成的盐*/private static RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();/*** 指定hash算法为MD5* 采用什么加密方式*/private static final String hashAlgorithmName = "md5";/*** 指定散列次数为1024次,即加密1024次* 加密1024次,解密也是1024次*/private static final int hashIterations = 1024;/*** true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储* 你是不是base64位的进行存储*/private static final boolean storedCredentialsHexEncoded = true;/*** 获得加密用的盐* 随机生成的盐* @return*/public static String createSalt() {return randomNumberGenerator.nextBytes().toHex();}/*** 获得加密后的凭证* 生成一个秘密* @param credentials 凭证(即密码)* @param salt 盐* @return* 原始密码 + 盐 = 加密后的 返回值String就是加密后的*/public static String createCredentials(String credentials, String salt) {SimpleHash simpleHash = new SimpleHash(hashAlgorithmName, credentials,salt, hashIterations);return storedCredentialsHexEncoded ? simpleHash.toHex() : simpleHash.toBase64();}/*** 进行密码验证* 校验我的密码** @param credentials 未加密的密码* @param salt 盐* @param encryptCredentials 加密后的密码* @return**/public static boolean checkCredentials(String credentials, String salt, String encryptCredentials) {return encryptCredentials.equals(createCredentials(credentials, salt));}public static void main(String[] args) {//盐 生成随机的盐String salt = createSalt();System.out.println(salt);
// 拿到盐生成的长度System.out.println(salt.length());//凭证+盐加密后得到的密码String credentials = createCredentials("123456", salt);System.out.println(credentials);
// 加密后的长度System.out.println(credentials.length());
// 拿到加密后的密码和原始化的密码如果为true,就代码加密成功了boolean b = checkCredentials("123456", salt, credentials);System.out.println(b);}
}
运行一下如图所示:
原始密码
盐
32
加密后
32
true
拿到原始密码和盐以及加密后的密码做对比如果为true说明加密成功
我们在运行一次看看这两者之间是不是一样的如图所示:
可以看到明显的不一样了,盐不一样了也就会导致加密后的也不一样了
如果说你有一万数据被泄露了,它要解密这些东西,它首先要拿到加密的次数(1024),要解密也的逐条进解密,因为我们每个加的盐都是不一样的。
我们怎么拿到数据库里的数据
我们查询的SQL语句也不一样了
之前的SQL语句查询
* from where ='zs' and =
现在的SQL语句查询
* from where ='zs'
假设:用户名: 密码:
传递到后台 就能接收到这两个变量
1.生成随机的盐
2.利用 原始密码 + 生成的盐 = 得到加密后的密码
3. 在执行 语句
二、shiro的认证
1.完成登录的方法 层的编写,接着就是biz层
2.完成自定义realm(重点)
3.与shiro的整合(注意)
4.测试
1.完成登录的方法 层的编写和biz层
通过逆向工程将五张表生成对应的model、
.xml 主要生成好了之后记得要把它切换掉为其他的
我们这就生成好了如图所示:
在我们的.xml中 新增方法
.java 也加上 我们刚刚写的方法
package com.jwj.ssm.mapper;import com.jwj.ssm.model.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;//这个加也可以不加也可以,不加那边的实现方法就会报红,会感觉不舒服,加了就不会报红
@Repository
public interface UserMapper {int deleteByPrimaryKey(Integer userid);int insert(User record);int insertSelective(User record);User selectByPrimaryKey(Integer userid);int updateByPrimaryKeySelective(User record);int updateByPrimaryKey(User record);User queryUserByUserName(@Param("userName") String userName);
}
.java
package com.jwj.ssm.biz;import com.jwj.ssm.model.User;
import org.apache.ibatis.annotations.Param;/*** @author 敢敢* @site www.javajwj.com* @company xxx公司* @create 2022-08-25 19:10*/
public interface UserBiz {int deleteByPrimaryKey(Integer userid);int insert(User record);int insertSelective(User record);User selectByPrimaryKey(Integer userid);int updateByPrimaryKeySelective(User record);int updateByPrimaryKey(User record);User queryUserByUserName(String userName);
}
实现类 .java
package com.jwj.ssm.biz.impl;import com.jwj.ssm.biz.UserBiz;
import com.jwj.ssm.mapper.UserMapper;
import com.jwj.ssm.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** @author 敢敢* @site www.javajwj.com* @company xxx公司* @create 2022-08-25 19:11*/
@Service("userBiz")
public class UserBizImpl implements UserBiz {@Autowiredprivate UserMapper userMapper;@Overridepublic int deleteByPrimaryKey(Integer userid) {return userMapper.deleteByPrimaryKey(userid);}@Overridepublic int insert(User record) {return userMapper.insert(record);}@Overridepublic int insertSelective(User record) {return userMapper.insertSelective(record);}@Overridepublic User selectByPrimaryKey(Integer userid) {return userMapper.selectByPrimaryKey(userid);}@Overridepublic int updateByPrimaryKeySelective(User record) {return userMapper.updateByPrimaryKeySelective(record);}@Overridepublic int updateByPrimaryKey(User record) {return userMapper.updateByPrimaryKey(record);}@Overridepublic User queryUserByUserName(String userName) {return userMapper.queryUserByUserName(userName);}
}
2.自定义realm(重点)
.java
package com.jwj.ssm.shiro;import com.jwj.ssm.biz.UserBiz;
import com.jwj.ssm.model.User;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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;/*** @author 敢敢* @site www.javajwj.com* @company xxx公司* @create 2022-08-25 19:19*/
public class MyRealm extends AuthorizingRealm {public UserBiz userBiz;public UserBiz getUserBiz() {return userBiz;}public void setUserBiz(UserBiz userBiz) {this.userBiz = userBiz;}/*** 授权* @param principalCollection* @return* shiro-web.ini*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}/*** 认证* @param authenticationToken* @return* @throws AuthenticationException* shiro.ini*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 拿到我们的用户名String userName = authenticationToken.getPrincipal().toString();User user = userBiz.queryUserByUserName(userName);
// 拿到数据库中的用户信息,放入token凭证中,用于controler进行对比AuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),ByteSource.Util.bytes(user.getSalt()),this.getName() //realm的名字);return info;}
}
交给我们的进行管理
.xml
3.与shiro的整合(注意)
①shiro 在加载的时候,上下文还没有加载完毕,所以@与@是不能使用的
② -shiro.xml 文件中,需要依赖的业务类,由于没有被配置,所以需要指定bean的id 通过@("具体的名字")
-shiro.xml
/user/login=anon/user/updatePwd.jsp=authc/admin/*.jsp=roles[admin]/user/teacher.jsp=perms["user:update"]
.java
package com.jwj.ssm.controller;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;/*** @author 敢敢* @site www.javajwj.com* @company xxx公司* @create 2022-08-20 12:12*/
@Controller
public class LoginController {// @RequestMapping("/login")
// public String login(HttpServletRequest request){登录成功一般需要 保存 用户信息
// String uname = request.getParameter("uname");
// if("zhangsan".equals(uname)){
// request.getSession().setAttribute("uname",uname);
// }
// return "index";
// }
//
// @RequestMapping("/logout")
// public String logout(HttpServletRequest request){做销毁
// request.getSession().invalidate();
// return "index";
// }@RequestMapping("/login")public String login(HttpServletRequest request){try {String username = request.getParameter("username");String password = request.getParameter("password");
// 生成令牌UsernamePasswordToken token = new UsernamePasswordToken(username,password);
// 生成主体Subject subject = SecurityUtils.getSubject();
// 拿到令牌进行登录subject.login(token);return "main";}catch (Exception e){request.setAttribute("message","账户密码错误...");return "login";}}@RequestMapping("/logout")public String logout(HttpServletRequest request){Subject subject = SecurityUtils.getSubject();subject.logout();return "login";}
}
4.测试
把这个复制到我们的下面
运行结果它也就那到了我们的用户名和盐以及加密如图所示:
最终运行结果如图所示:
‘
结论:nfo认证方法是web层执行.login 方法触发的。
三、总结 1.盐加密
1.明文密码
2.md5 加密 密文密码
3.md5 加盐加密 一个明文对应多个密文
4.md5 加盐加密加次数
2.shiro 的认证
1.层 —— 通过账户名获取用户信息
2.将用户信息给 认证方法,认证的过程交给安全管理器
3.的配置,配置-shiro.xml 文件中
① shiro接管的时候,还没有被所接管导致@与@用不了
② 采用配置的形式配置,需要给@指定bean的名称