• 盐加密的了解和shiro认证-SSM


    目录

    本次目标:

    一、盐加密

    1. 什么是盐加密

    2. 数据库密码的发展史

    二、Shiro认证

    1. 配置环境

    2.完成登录的方法 Mapper层的编写,接着biz层

    3. 完成自定义realm(重点)

    4.Spring与shiro的整合(注意)


    本次目标:

    1. 盐加密
    2. shiro认证

    一、盐加密

    1. 什么是盐加密

    加盐加密是一种对系统登录口令的加密方式,它实现的方式是将每一个口令同一个叫做”盐“(salt)的n位随机数相关联。

    无论何时只要口令改变,随机数就改变。随机数以未加密的方式存放在口令文件中,这样每个人都可以读。

    不再只保存加密过的口令,而是先将口令和随机数连接起来然后一同加密,加密后的结果放在口令文件中。

    2. 数据库密码的发展史

    (md5就是一种信息摘要加密算法。)

    第一个阶段:明文密码
    第二个阶段:md5加密
    第三个阶段:md5加盐加密
    第四个阶段:md5加盐加密加次数

    随机器生成的,次数是自己定义的。 

    加密地址:md5解密加密

    示例:

    PasswordHelper

    1. package com.ps.shiro;
    2. import org.apache.shiro.crypto.RandomNumberGenerator;
    3. import org.apache.shiro.crypto.SecureRandomNumberGenerator;
    4. import org.apache.shiro.crypto.hash.SimpleHash;
    5. /**
    6. * 用于shiro权限认证的密码工具类
    7. */
    8. public class PasswordHelper {
    9. /**
    10. * 随机数生成器
    11. */
    12. private static RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
    13. /**
    14. * 指定hash算法为MD5
    15. */
    16. private static final String hashAlgorithmName = "md5";
    17. /**
    18. * 指定散列次数为1024次,即加密1024次
    19. */
    20. private static final int hashIterations = 1024;
    21. /**
    22. * true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储
    23. */
    24. private static final boolean storedCredentialsHexEncoded = true;
    25. /**
    26. * 获得加密用的盐
    27. *
    28. * @return
    29. */
    30. public static String createSalt() {
    31. return randomNumberGenerator.nextBytes().toHex();
    32. }
    33. /**
    34. * 获得加密后的凭证
    35. *
    36. * @param credentials 凭证(即密码)
    37. * @param salt 盐
    38. * @return
    39. */
    40. public static String createCredentials(String credentials, String salt) {
    41. SimpleHash simpleHash = new SimpleHash(hashAlgorithmName, credentials,
    42. salt, hashIterations);
    43. return storedCredentialsHexEncoded ? simpleHash.toHex() : simpleHash.toBase64();
    44. }
    45. /**
    46. * 进行密码验证
    47. *
    48. * @param credentials 未加密的密码
    49. * @param salt 盐
    50. * @param encryptCredentials 加密后的密码
    51. * @return
    52. */
    53. public static boolean checkCredentials(String credentials, String salt, String encryptCredentials) {
    54. return encryptCredentials.equals(createCredentials(credentials, salt));
    55. }
    56. public static void main(String[] args) {
    57. //盐
    58. String salt = createSalt();
    59. System.out.println(salt);
    60. System.out.println(salt.length());
    61. //凭证+盐加密后得到的密码
    62. String credentials = createCredentials("123456", salt);
    63. System.out.println(credentials);
    64. System.out.println(credentials.length());
    65. boolean b = checkCredentials("123456", salt, credentials);
    66. System.out.println(b);
    67. }
    68. }

    运行结果:

    二、Shiro认证

    1. 配置环境

    pom依赖

    1. <dependency>
    2. <groupId>org.apache.shirogroupId>
    3. <artifactId>shiro-coreartifactId>
    4. <version>1.3.2version>
    5. dependency>
    6. <dependency>
    7. <groupId>org.apache.shirogroupId>
    8. <artifactId>shiro-webartifactId>
    9. <version>1.3.2version>
    10. dependency>
    11. <dependency>
    12. <groupId>org.apache.shirogroupId>
    13. <artifactId>shiro-springartifactId>
    14. <version>1.3.2version>
    15. dependency>

    web.xml配置

    1. <filter>
    2. <filter-name>shiroFilterfilter-name>
    3. <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
    4. <init-param>
    5. <param-name>targetFilterLifecycleparam-name>
    6. <param-value>trueparam-value>
    7. init-param>
    8. filter>
    9. <filter-mapping>
    10. <filter-name>shiroFilterfilter-name>
    11. <url-pattern>/*url-pattern>
    12. filter-mapping>

    2.完成登录的方法 Mapper层的编写,接着biz

    (逆向生成的表是放在generatorConfig.xml中)

    UserMapper.xml

    1. <select id="queryUserByUserName" resultType="com.ps.ssm.model.User" parameterType="java.lang.String" >
    2. select
    3. <include refid="Base_Column_List" />
    4. from t_shiro_user
    5. where username = #{userName}
    6. select>

    UserMapper.java

      User queryUserByUserName(@Param("userName") String userName);

    UserBiz.java

    1. package com.ps.ssm.biz;
    2. import com.ps.ssm.model.User;
    3. import org.apache.ibatis.annotations.Param;
    4. public interface UserBiz {
    5. int deleteByPrimaryKey(Integer userid);
    6. int insert(User record);
    7. int insertSelective(User record);
    8. User selectByPrimaryKey(Integer userid);
    9. User queryUserByUserName(@Param("userName") String userName);
    10. int updateByPrimaryKeySelective(User record);
    11. int updateByPrimaryKey(User record);
    12. }

    UserBizImpl.java

    1. package com.ps.ssm.biz.imp;
    2. import com.ps.ssm.biz.UserBiz;
    3. import com.ps.ssm.mapper.UserMapper;
    4. import com.ps.ssm.model.User;
    5. import org.springframework.beans.factory.annotation.Autowired;
    6. import org.springframework.stereotype.Service;
    7. /**
    8. * @author 彭于晏
    9. * @site www.pengyuyan.com
    10. * @company 玉渊工作室
    11. * @create 2022-08-26 12:19
    12. */
    13. @Service
    14. public class UserBizImpl implements UserBiz {
    15. @Autowired
    16. private UserMapper userMapper;
    17. @Override
    18. public int deleteByPrimaryKey(Integer userid) {
    19. return userMapper.deleteByPrimaryKey(userid);
    20. }
    21. @Override
    22. public int insert(User record) {
    23. return userMapper.insert(record);
    24. }
    25. @Override
    26. public int insertSelective(User record) {
    27. return userMapper.insertSelective(record);
    28. }
    29. @Override
    30. public User selectByPrimaryKey(Integer userid) {
    31. return userMapper.selectByPrimaryKey(userid);
    32. }
    33. @Override
    34. public User queryUserByUserName(String userName) {
    35. return userMapper.queryUserByUserName(userName);
    36. }
    37. @Override
    38. public int updateByPrimaryKeySelective(User record) {
    39. return userMapper.updateByPrimaryKeySelective(record);
    40. }
    41. @Override
    42. public int updateByPrimaryKey(User record) {
    43. return userMapper.updateByPrimaryKey(record);
    44. }
    45. }

    3. 完成自定义realm(重点)

    • ShiroRealm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;
    • 也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源
    • 最基础的是Realm接口CachingRealm负责缓存处理AuthenticationRealm负责认证AuthorizingRealm负责授权

    AuthorizationInfo:授权信息
    AuthenticationInfo:认证信息 

    Realm体系结构:

    自定义Realm—MyRealm

    1. package com.ps.ssm.shiro;
    2. import com.ps.ssm.biz.UserBiz;
    3. import com.ps.ssm.model.User;
    4. import org.apache.shiro.authc.AuthenticationException;
    5. import org.apache.shiro.authc.AuthenticationInfo;
    6. import org.apache.shiro.authc.AuthenticationToken;
    7. import org.apache.shiro.authc.SimpleAuthenticationInfo;
    8. import org.apache.shiro.authz.AuthorizationInfo;
    9. import org.apache.shiro.realm.AuthorizingRealm;
    10. import org.apache.shiro.subject.PrincipalCollection;
    11. import org.apache.shiro.util.ByteSource;
    12. /**
    13. * @author 彭于晏
    14. * @site www.pengyuyan.com
    15. * @company 玉渊工作室
    16. * @create 2022-08-26 12:45
    17. */
    18. public class MyRealm extends AuthorizingRealm {
    19. public UserBiz userBiz;
    20. public UserBiz getUserBiz() {
    21. return userBiz;
    22. }
    23. public void setUserBiz(UserBiz userBiz) {
    24. this.userBiz = userBiz;
    25. }
    26. /**
    27. * 授权
    28. * @param principals
    29. * @return
    30. * 替代shiro-web-ini
    31. */
    32. @Override
    33. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    34. return null;
    35. }
    36. /**
    37. * 认证
    38. * @param token
    39. * @return
    40. * @throws AuthenticationException
    41. * 替代shiro.ini
    42. */
    43. @Override
    44. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    45. //调用查询方法
    46. String userName = token.getPrincipal().toString();
    47. User user = userBiz.queryUserByName(userName);
    48. AuthenticationInfo info = new SimpleAuthenticationInfo(
    49. user.getUsername(),
    50. user.getPassword(),
    51. ByteSource.Util.bytes(user.getSalt()),
    52. this.getName()//realm的名字
    53. );
    54. return info;
    55. }
    56. }

    application-shiro配置

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <bean id="shiroRealm" class="com.ps.ssm.shiro.MyRealm">
    6. <property name="userBiz" ref="userBiz" />
    7. <property name="credentialsMatcher">
    8. <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    9. <property name="hashAlgorithmName" value="md5"/>
    10. <property name="hashIterations" value="1024"/>
    11. <property name="storedCredentialsHexEncoded" value="true"/>
    12. bean>
    13. property>
    14. bean>
    15. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    16. <property name="realm" ref="shiroRealm" />
    17. bean>
    18. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    19. <property name="securityManager" ref="securityManager" />
    20. <property name="loginUrl" value="/login"/>
    21. <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    22. <property name="filterChainDefinitions">
    23. <value>
    24. /user/login=anon
    25. /user/updatePwd.jsp=authc
    26. /admin/*.jsp=roles[admin]
    27. /user/teacher.jsp=perms["user:update"]
    28. value>
    29. property>
    30. bean>
    31. <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    32. beans>

    applicationContext.xml:

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    5. xmlns:aop="http://www.springframework.org/schema/aop"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    7. <import resource="applicationContext-mybatis.xml">import>
    8. <import resource="applicationContext-shiro.xml">import>
    9. beans>

    4.Spring与shiro的整合(注意)

    ShiroUserController

    1. package com.ps.ssm.controller;
    2. import org.apache.shiro.SecurityUtils;
    3. import org.apache.shiro.authc.UsernamePasswordToken;
    4. import org.apache.shiro.subject.Subject;
    5. import org.springframework.stereotype.Controller;
    6. import org.springframework.web.bind.annotation.RequestMapping;
    7. import javax.servlet.http.HttpServletRequest;
    8. /**
    9. * @author 彭于晏
    10. * @site www.pengyuyan.com
    11. * @company 玉渊工作室
    12. * @create 2022-08-26 13:11
    13. */
    14. @Controller
    15. public class ShiroUserController {
    16. @RequestMapping("/login")
    17. public String login(HttpServletRequest request){
    18. try {
    19. //传入
    20. String username = request.getParameter("username");
    21. String password = request.getParameter("password");
    22. //令牌
    23. UsernamePasswordToken token = new UsernamePasswordToken(username,password);
    24. //拿到当前登录主题
    25. Subject subject = SecurityUtils.getSubject();
    26. //通过登录主题进行登录
    27. subject.login(token);
    28. return "main";
    29. }catch (Exception e){
    30. request.setAttribute("message","账号密码错误");
    31. return "login";
    32. }
    33. }
    34. @RequestMapping("/logout")
    35. public String logout(HttpServletRequest request){
    36. //拿到登录主体
    37. Subject subject = SecurityUtils.getSubject();
    38. subject.logout();
    39. return "login";
    40. }
    41. }

    工具类:PasswordHelper

    1. package com.ps.shiro;
    2. import org.apache.shiro.crypto.RandomNumberGenerator;
    3. import org.apache.shiro.crypto.SecureRandomNumberGenerator;
    4. import org.apache.shiro.crypto.hash.SimpleHash;
    5. /**
    6. * 用于shiro权限认证的密码工具类
    7. */
    8. public class PasswordHelper {
    9. /**
    10. * 随机数生成器(生成盐)
    11. */
    12. private static RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
    13. /**
    14. * 指定hash算法为MD5
    15. */
    16. private static final String hashAlgorithmName = "md5";
    17. /**
    18. * 指定散列次数为1024次,即加密1024次
    19. */
    20. private static final int hashIterations = 1024;
    21. /**
    22. * true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储
    23. */
    24. private static final boolean storedCredentialsHexEncoded = true;
    25. /**
    26. * 获得加密用的盐(生成一个随机的盐)
    27. *
    28. * @return
    29. */
    30. public static String createSalt() {
    31. return randomNumberGenerator.nextBytes().toHex();
    32. }
    33. /**
    34. * 获得加密后的凭证
    35. *
    36. * @param credentials 凭证(即密码)
    37. * @param salt 盐
    38. * @return
    39. */
    40. public static String createCredentials(String credentials, String salt) {
    41. SimpleHash simpleHash = new SimpleHash(hashAlgorithmName, credentials,
    42. salt, hashIterations);
    43. return storedCredentialsHexEncoded ? simpleHash.toHex() : simpleHash.toBase64();
    44. }
    45. /**
    46. * 进行密码验证
    47. *
    48. * @param credentials 未加密的密码
    49. * @param salt 盐
    50. * @param encryptCredentials 加密后的密码
    51. * @return
    52. */
    53. public static boolean checkCredentials(String credentials, String salt, String encryptCredentials) {
    54. return encryptCredentials.equals(createCredentials(credentials, salt));
    55. }
    56. public static void main(String[] args) {
    57. //盐
    58. String salt = createSalt();
    59. System.out.println(salt);
    60. System.out.println(salt.length());
    61. //凭证+盐加密后得到的密码
    62. String credentials = createCredentials("123456", salt);
    63. System.out.println(credentials);
    64. System.out.println(credentials.length());
    65. boolean b = checkCredentials("123456", salt, credentials);
    66. System.out.println(b);
    67. }
    68. }

    测试:

     

    今天分享的知识就到这里啦!如果喜欢,那就关注博主,了解更多的知识吧!

  • 相关阅读:
    LeetCode-46-全排列
    hbase学习
    Python散点图
    现代企业架构框架-数据架构
    ue4项目运行还可以鼠标点击
    uniapp(uncloud) 使用生态开发接口详情2(使用 schema创建数据, schema2code创建页面, iconfont 引入项目)
    复旦微开发过程中遇到的问题总结(三)
    【Redis】理论进阶篇------浅谈Redis的缓存穿透和雪崩原理
    【C++】日期类的实现
    typeorm 批量插入数据优化和插入冲突操作
  • 原文地址:https://blog.csdn.net/weixin_63531940/article/details/126530554