1.注册

1.1 注册流程

  1. 用户输入用户名密码进行注册。

  2. 服务端收到用户名密码之后,进行一个加密处理,然后再存到数据库中。

    //带盐的加密字符串
    Md5Hash zhangsan = new Md5Hash("123", "zhangsan", 1024);
    System.out.println("zhangsan = " + zhangsan);
    SimpleHash simpleHash = new SimpleHash("MD5", "123", "lisi", 1024);
    System.out.println("simpleHash = " + simpleHash);
    

    加密之后,将加密后的密码存入到数据库中。

2.登录

2.1 登录流程

  1. 登录的时候用户输入用户名密码。
  2. 登录时候,主要在 com.qfedu.demo.realm.DbRealm#doGetAuthenticationInfo 方法中处理登录逻辑,这个方法主要是根据登录用户名去数据库查询到用户信息,并返回。
  3. 系统会自动调用 com.qfedu.demo.realm.DbRealm#getCredentialsMatcher 方法中提供的密码比对器,做最后的密码比对操作。

3.登录加密验证

3.1数据库

我们这里设置六个字段

  1. id 用户id
  2. username用户名 —>以后都是用用户名进行加盐操作
  3. password用户密码—> 密码以后要进行加密,有两种加密方法
    1. MD5
    2. SHA-512
  4. nickname暂时用不到
  5. 权限名(boolean类型)1,0
  6. 用户权限类型

3.2 密码加密过程

由于我们这里没有写登录功能,我们在测试方法里手动进行密码加密,更便于理解

MainTest

//第一种加密方法,写法不同, 利用 MD5 消息摘要计算 123 的消息摘要Md5Hash md5Hash = new Md5Hash("123");System.out.println("md5Hash = " + md5Hash);
//也可以指定SimpleHash,因为MD5Hash是SimpleHash的子类SimpleHash md5 = new SimpleHash("MD5", "123");System.out.println("md5 = " + md5);//第二种加密方法,写法不同,利用SHA512信息摘要计算123的信息摘要System.out.println("-------------------------------------");System.out.println("new Sha512Hash(\"123\") = " + new Sha512Hash("123"));System.out.println("new SimpleHash(\"SHA-512\",\"123\") = " + new SimpleHash("SHA-512", "123"));

密码加密结果:

3.3 controller层如何调用密码加密并且验证

@Component
public class DBRealm extends AuthenticatingRealm {@AutowiredUserMapper userMapper;@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken toKen) throws AuthenticationException {//当前登录的用户名和密码都在token里面保存UsernamePasswordToken usernamePasswordToken =(UsernamePasswordToken) toKen;String username = usernamePasswordToken.getUsername();Users users = userMapper.getUserByUsername(username);if (users == null){throw new UnknownAccountException("用户名输入错误");}if (!users.getEnabled()){throw new LockedAccountException("账号被锁定,登录失败");}/*传入方法的参数:1.用户登录的用户名* 2.用户的密码,注意,这个密码是从数据库查询出来的用户密码* 3.这里返回之后,系统会根据这里返回的信息,再结合用户登录时输入的用户名密码信息去判断密码是否正确* */return new SimpleAuthenticationInfo(users.getUsername(), users.getPassword(),getName());}@Overridepublic CredentialsMatcher getCredentialsMatcher() {//这里返回的是SHA-512加密方式的密码的信息摘要给数据库,所以我们要手动给数据库的password中添加,MainTest的SHA-512加密方式的信息摘要return new HashedCredentialsMatcher("SHA-512");}

3.4补充1( MD5Hash第二种加密的原因):

MD5Hash是SimpleHash的子类,所以我们也可以用SimpleHash去进行MD5的加密,但是要添加加密方式

补充2:

3.5 Shiro底层之密码如何比对

第一步:首先我们在登录界面进入token,因为我们的用户名和密码都是存储在这个token里面

第二步:

第三步:

我们controller层的方法,返回的是同一个AuthentiationInfo

第四步骤

我们来看看authenticate方法做了什么

补充: 如果我们设置了多个Realm,就要跟第六小节一样去配置多个Realm,我们这里只写了一个Realm

第五步 再进入方法

getRealms方法的作用:这个方法来进行判断我们有几个Realms,

如果有多个就进入到多个的处理逻辑,

即doMultiRealmAuthentication这个里面去

有单个就进入到单个的处理逻辑。

即doSingleRealmAuthentication这个里面去

我们这里只有一个Realm,就先进入单个处理逻辑的方法

第六步 进入单个处理逻辑doSingleRealmAuthentication

第七步:进入这个doGetAuthenticationInfo的父类

GetAuthenticationInfo看他做了什么

这样就顺利的调用到了我们的DBRealm

第八步:我们的DBrealm返回了什么呢

第九步:继续看返回了什么

9.1.得到了返回的info

9.2 这个info里包含了我们的认证信息(从数据中传出来的)

9.3 然后再把这个(后端)info和(前端)token丢入我们的cache缓存中去,这样下一次我们就不用执行这一些代码,

  1. info返回信息:info如果不等于Null,即我们的info是有值的话怎么返回info信息给我们的DBrealm里面的调用方法,通过assertCredentialsMatch()进行密码的比对!

要是token和info不相同的话,就去抛异常,那密码是怎么进行比对的呢?

  1. 进入**assertCredentialsMatch()**方法看这个方法怎么进行密码的比对

11.1 我们在我们的AuthenticatingRealm里面也就是我们的DBRealm里调用了

getCredentialsMatcher()

这是一个接口对接了我们的密码比对器(shrio默认提供的)

SimpleCredentialsMatcher这个就是默认提供给我们的密码比对器

那我们的密码比对器做了什么

12.进入密码比对器SimpleCredentialsMatcher

步骤:

1.从token中拿到用户的数据数组

2.accountcredentials中拿到用户登录的字符串

3.equal方法比较两者值是否相等

13.equals比较

4.登录验证+加密+加盐

加密+加盐方式与上面大同小异但是不同的是要多加一个参数,也是用到上面的SimpleHash或者它的子类们。

       //带盐的加密字符串//第一种MD5加密方法加密,加盐Md5Hash sang = new Md5Hash("123", "sang", 1024);System.out.println("sang = " + sang);System.out.println("--------------------------------------------------");System.out.println("--------------------------------------------------");//第二种SHA-512加盐加密//加密加盐Sha512Hash sha512Hash=new Sha512Hash("123","sang",1024);System.out.println("--------------------------------------------------");SimpleHash simpleHash = new SimpleHash("SHA-512", "123", "sang", 1024);System.out.println("simpleHash = " + simpleHash);

controller调用方式与上面类似

5.RememberMe

概念:在服务端对所有的接口做一个分类,不涉及到数据修改的安全性较低的设置RememberMe

注意:RememberMe 也是一种认证的方式,不一定说所有的登录都有用账户名和密码进行登录(是便捷和用户安全之间的一种平衡)

5.1登录流程

  1. 登录的时候,传入用户名密码,登录成功之后,先对当前登录的用户进行序列化,序列化之后,得到一个 byte 数组,然后对这个 byte 数组进行加密(用的是 AES 对称加密,将来可以解密的),加密之后得到一个 byte 数组,但是这个 byte 数组无法直接展示出来,需要再进行一次 Base64 转码,就可以转为可读的字符串了,然后将这个字符串写入到 Cookie 中,并返回给浏览器。

5.2 验证流程

  1. 以后每次请求的时候,系统都会自动携带上这个 Cookie,系统收到这个 Cookie 之后,首先从请求头中提取出 RememberMe 字符串,提取出来之后首先进行 Base64 解码,解码之后,再调用 AES 服务进行解密,揭秘之后得到一个 byte 数组,再将这个 byte 数组反序列化,得到登录的用户对象。

5.3 用法

login.jsp中添加 参数

  <form action="/m/doLogin" method="post"><input type="text" name="username" value="sang"><input type="password" name="password" value="123"><input type="checkbox" value="true" name="rememberMe">rememberMe<input type="submit" value="登录"></form>

LoginController

 @PostMapping("/doLogin")//1.字符串传入参数(因为里面肯定带了数据所以设置为String类型)public String doLogin(String username, String password, Model model,String rememberMe) {//获取当前用户Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(username, password);try {//2.登录操作之前if ("on".equals(rememberMe)){token.setRememberMe(true);}subject.login(token);return "redirect:/hello";} catch (AuthenticationException e) {e.printStackTrace();model.addAttribute("error", e.getMessage());}return "forward:/login";}

注意:

1.字符串传入参数(因为里面肯定带了数据所以设置为String类型)

2.使用密码比对器进行密码比对前,先对获取到的携带RememberMe 的数据进行判断,是否可以使用

6.配置多个Realm

6.1 使用场景:

当商家和用户登录权限相同,管理员跟上面两者权限不同的时候,用一个接口来处理商家和用户登录权限

6.2 Realm的配置

1.AtLeastOneSuccessfulStrategy (org.apache.shiro.authc.pam):至少有一个 Realm 认证成功,就算成功

2.AllSuccessfulStrategy (org.apache.shiro.authc.pam):所有 Realm 都要认证成功才算成功

3.FirstSuccessfulStrategy (org.apache.shiro.authc.pam):至少有一个 Realm 认证成功,就算成功,这个 Bean 中,有一个属性名为 stopAfterFirstSuccess,表示是否在第一个 bean 认证成功后,就不再执行后面的 Realm 了,这个属性默认为 false,即第一个 Reaml 认证成功后,后面的 Realm 还是会认证的.

​ 此时 FirstSuccessfulStrategy 和 AtLeastOneSuccessfulStrategy 其实没有差别。

如果将 stopAfterFirstSuccess 属性设置为 true,
那么对于 FirstSuccessfulStrategy 而言,
第一个 Realm 认证成功后,后面的 Realm 就不再执行了。

<!--
这个是配置多 Realm 的认证器AtLeastOneSuccessfulStrategy (org.apache.shiro.authc.pam):至少有一个 Realm 认证成功,就算成功AllSuccessfulStrategy (org.apache.shiro.authc.pam):所有 Realm 都要认证成功才算成功FirstSuccessfulStrategy (org.apache.shiro.authc.pam):至少有一个 Realm 认证成功,就算成功,这个 Bean 中,有一个属性名为 stopAfterFirstSuccess,
表示是否在第一个 bean 认证成功后,就不再执行后面的 Realm 了,
这个属性默认为 false,
即第一个 Reaml 认证成功后,
后面的 Realm 还是会认证的,此时 FirstSuccessfulStrategy 和 AtLeastOneSuccessfulStrategy 其实没有差别。
如果将 stopAfterFirstSuccess 属性设置为 true,
那么对于 FirstSuccessfulStrategy 而言,
第一个 Realm 认证成功后,后面的 Realm 就不再执行了。
--><bean class="org.apache.shiro.authc.pam.ModularRealmAuthenticator" id="authenticator"><!--设置多个 realm --><property name="realms"><list><ref bean="DBRealm"/><ref bean="DBSaleMi"/></list></property><!--AtLeastOneSuccessfulStrategy,身份验证类--><property name="authenticationStrategy"><bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"/></property></bean><!--配置Realm-->
<!--    <bean class="com.huang.demo.realm.DBRealm" id="dbRealm"/>--><bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager"><property name="realm" ref="DBRealm"/><property name="sessionManager" ><bean class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"><property name="sessionIdUrlRewritingEnabled" value="false"/></bean></property></bean><bean class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" id="shiroFilter"><property name="securityManager"  ref="securityManager"/><property name="loginUrl" value="/login" /><property name="filterChainDefinitions"><!--/login=anon 表示 /login 这个路径可以匿名访问/logout=logout 后面的 logout 是注销登录过滤器的简称/**=authc 表示其余的请求,都要认证之后才能访问注意这里的顺序--><value>/logout=logout/login=anon/doLogin=anon/**=authc</value></property></bean>

7.不同的密码比对器

SimplecredentialsMatcher

密码比对器

我们通过SimplecredentialsMatcher密码比对器进行密码比对,他的下面有很多的不同的密码比对的方法。那我们改怎么使用他?

注意:小节3中的例子是没有经过加密的,所有我们可以直接去使用SimplecredentialsMatcher这个密码比对器进行密码比对,

  • 但是如果我们使用了MD5进行加密。那我们就要去使用SimplecredentialsMatcher的子类Md5CredentialsMatcher()

    • 注意:这个方法废弃了
    • 我们使用return new HashedCredentialsMatcher(“MD5”)的方式
  • 用SHA-512一样
/login=anon/doLogin=anon/**=authc</value></property>
</bean>
# 7.不同的密码比对器SimplecredentialsMatcher密码比对器[外链图片转存中...(img-azXihmGW-1657209765342)]我们通过SimplecredentialsMatcher密码比对器进行密码比对,他的下面有很多的不同的密码比对的方法。那我们改怎么使用他?> 注意:小节3中的例子是没有经过加密的,所有我们可以直接去使用SimplecredentialsMatcher这个密码比对器进行密码比对,
>
> + 但是如果我们使用了MD5进行加密。那我们就要去使用SimplecredentialsMatcher的子类Md5CredentialsMatcher()
>   + 注意:这个方法废弃了
>   + 我们使用return new HashedCredentialsMatcher("MD5")的方式
> + 用SHA-512一样

shiro注册登录流程(如何加密加盐)+配置多个Ream+密码加密验证底层分析+Remember使用+不同密码比对器原理(二)相关推荐

  1. 加解密篇 - 什么是加密加盐 (分析web3j的加盐处理)

    这篇是加解密的最后一篇,来聊聊加密加盐.翻看最近的区块链钱包项目,发现 web3j 的源码中对数据做了加盐处理,正好分析一下它是如何进行加盐处理的. 目录: 什么是加盐 加盐的原理和流程 加盐 dem ...

  2. java加盐_Java中MD5加密加盐算法

    前俩天项目组需要做一个密码的加密加盐操作,无意中在网上看到一个对应的加密加盐算法,特意在此做一个记录 import java.security.MessageDigest; import java.u ...

  3. BCrypt加密怎么存入数据库_Spring Boot 中密码加密的两种姿势

    1.为什么要加密 2.加密方案 3.实践3.1 codec 加密3.2 BCryptPasswordEncoder 加密 4.源码浅析 先说一句:密码是无法解密的.大家也不要再问松哥微人事项目中的密码 ...

  4. 关于Shiro使用密码加密加盐之后序列化失败的问题(十四)

    原文:https://blog.csdn.net/qq_34021712/article/details/84567437 shiro使用密码加盐之后,序列化失败 ERROR Failed to se ...

  5. 抖音实战~手机号密码一键注册登录流程(限制手机终端登录)

    文章目录 一.手机号+密码 二.前端 2.1. 点击登陆流程 2.2. 点击登录源码 三.后端登录 3.1. 登录流程图 3.2. 流程简述 3.3. 手机号验证码登录流程 一.手机号+密码 二.前端 ...

  6. 密码加密 加盐 Java PBKDF2 密码哈希代码

    如果你是Web开发者,你很可能需要开发一个用户账户系统.这个系统最重要的方面,就是怎样保护用户的密码.存放帐号的数据库经常成为入侵的目标,所以你必须做点什么来保护密码,以防网站被攻破时发生危险.最好的 ...

  7. MD5加密以及验证加密-加盐

    加密与解密算法: /// <summary> /// 签名字符串 32位 /// </summary> /// <param name="input" ...

  8. kaggle网站注册登录流程详细介绍(小白必看)

    Kaggle是一个为数据科学和机器学习提供竞赛.数据集和工具的在线平台. 该网站通过向用户提供不同领域的实际问题和数据集,吸引了全球数据科学家和机器学习从业者的关注.Kaggle还为用户提供机器学习模 ...

  9. 抖音实战~手机号验证码一键注册登录流程(限制手机终端登录)

    文章目录 一.手机号+验证码 二.前端 2.1. 点击登陆流程 2.2. 点击登录源码 三.后端登录 3.1. 登录流程图 3.2. 流程简述 3.3. 手机号验证码登录流程 一.手机号+验证码 二. ...

  10. Laravel后端接口使用mews/captcha验证码注册+登录流程讲解

    大致的流程讲解: 注册流程: 获取图形验证码并正确填写->请求注册验证短信->填写注册的用户信息+短信验证码->用户注册成功 登录流程: 前端请求短信->已注册用户:返回登录的 ...

最新文章

  1. 结构体中最后一个成员为[0]或[1]长度数组(柔性数组成员)的用法
  2. 如何把百万级别的订单根据金额排序
  3. Windows 7防火墙配置FTP相关
  4. github上传代码
  5. 响应式web(一):什么是响应式web,异步调用,callback的本质,servlet3的异步
  6. uva 12589——Learning Vector
  7. 面试加分项!Android权限处理,手慢无
  8. 【51Nod - 1279】 扔盘子(思维)(on-p会超时)
  9. IIFP之牛刀小试(初识篇)
  10. Android零碎要点---eclipse两个小技巧
  11. 【Vue2.0】—常用的内置指令(九)
  12. 单片机语音识别源码与资料(ASR M08-B模块arduino与51驱动)
  13. deeplearning4j的学习
  14. ai 2.5d插件_【插画AI教程】从0到1,学会16 种热门插画设计风格!
  15. Android触控签名软件,Android Sign Kit(app一键签名)
  16. 计算机学院 名言,计算机系网络毕业名言
  17. oj趣味题:柱状图排序
  18. 联想存储8GB缓存00MJ101大量现货做工精细
  19. 略胜知云?适合大学生的一款文献翻译神器,网页版工具
  20. 超级总结:vs2008/2005 sp1 C++ 发布程序 .

热门文章

  1. 路由器信号分为2.4G和5G,有什么区别?
  2. 荣耀4a鸿蒙,华为 Plan B 揭开面纱:鸿蒙要超越安卓?小米 OPPO 们买单吗?
  3. 快速分析京东物流详情,并导出EXCEL表格
  4. 欧几里得gcd与拓展欧几里得exgcd
  5. 安卓实训项目源码_实训2019 | 联想云实训心得
  6. 输入某年某日,判断这一天是这一年的第几天
  7. c语言.jpg图片转成数组_JPG图片怎么转换成PDF?可以试试这些转换方法!
  8. 【docker详解02】-docker安装
  9. Vue3和Vue2的一些区别
  10. Java日志门面担当-SLF4J