shiro加盐走源码
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
/* */ throws AuthenticationException
/* */ {
/* 565 */ AuthenticationInfo info = getCachedAuthenticationInfo(token);
/* 566 */ if (info == null)
/* */ {
/* 568 */ info = doGetAuthenticationInfo(token);一、
/* 569 */ log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
/* 570 */ if ((token != null) && (info != null))
/* 571 */ cacheAuthenticationInfoIfPossible(token, info);二、
/* */ }
/* */ else {
/* 574 */ log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
/* */ }
/* *//* 577 */ if (info != null)
/* 578 */ assertCredentialsMatch(token, info);三、这个是重点
/* */ else {
/* 580 */ log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token);
/* */ }
/* *//* 583 */ return info;
/* */ }
一、doGetAuthenticationInfo(token)方法
/* */ private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, AuthenticationInfo info)
/* */ {
/* 506 */ if (!(isAuthenticationCachingEnabled(token, info))) {
/* 507 */ log.debug("AuthenticationInfo caching is disabled for info [{}]. Submitted token: [{}].", info, token);
/* *//* 509 */ return;
/* */ }
/* *//* 512 */ Cache cache = getAvailableAuthenticationCache();
/* 513 */ if (cache != null) {
/* 514 */ Object key = getAuthenticationCacheKey(token);
/* 515 */ cache.put(key, info);
/* 516 */ log.trace("Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].", key, info);
/* */ }
/* */ }进入方法:
isAuthenticationCachingEnabled(token, info)/* */ protected boolean isAuthenticationCachingEnabled(AuthenticationToken token, AuthenticationInfo info)
/* */ {
/* 536 */ return isAuthenticationCachingEnabled();
/* */ }
/* */ protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)
/* */ throws AuthenticationException
/* */ {
/* 595 */ CredentialsMatcher cm = getCredentialsMatcher();一、
/* 596 */ if (cm != null) {
/* 597 */ if (cm.doCredentialsMatch(token, info))二、这个方法更重要,正式比较开始了
/* */ return;
/* 599 */ String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
/* 600 */ throw new IncorrectCredentialsException(msg);
/* */ }
/* *//* 603 */ throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify credentials during authentication. If you do not wish for credentials to be examined, you can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
/* */ }一、CredentialsMatcher cm = getCredentialsMatcher();
一、方法:重要的看下面图片:
/* */ public CredentialsMatcher getCredentialsMatcher()
/* */ {
/* 194 */ return this.credentialsMatcher;
/* */ }二、cm.doCredentialsMatch(token, info) **********
二、看代码,这里的token和info还是咱们截图的信息
/* */ public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)
/* */ {
/* 379 */ Object tokenHashedCredentials = hashProvidedCredentials(token, info);二A
/* 380 */ Object accountCredentials = getCredentials(info);
/* 381 */ return equals(tokenHashedCredentials, accountCredentials);
/* */ }
二AhashProvidedCredentials(token, info)
进入这个方法:
/* */ protected Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info)
/* */ {
/* 403 */ Object salt = null;
/* 404 */ if (info instanceof SaltedAuthenticationInfo) {
/* 405 */ salt = ((SaltedAuthenticationInfo)info).getCredentialsSalt();二AA
/* *//* */ }
/* 408 */ else if (isHashSalted()) {
/* 409 */ salt = getSalt(token);
/* */ }
/* *//* 412 */ return hashProvidedCredentials(token.getCredentials(), salt, getHashIterations());二AB
/* */ }salt = ((SaltedAuthenticationInfo)info).getCredentialsSalt();二AA
这里你就会发现,为什么在info里面设置ByteSource了
进入二AA
/* */ public ByteSource getCredentialsSalt()
/* */ {
/* 167 */ return this.credentialsSalt;
/* */ }
hashProvidedCredentials(token.getCredentials(), salt, getHashIterations());二AB
进入二AB
这三个参数的截图我放下面,大家看,其实第一个是用户输入的密码,第二个是上面算出的盐,第三个是散列次数三,
这几个参数里面除了密码是用户输入的,其他俩个参数都是shiroconfigura里面配置的
见图--我是盐jpg,我是散列次数jpg
我们进入该方法:
/* */ protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations)
/* */ {
/* 444 */ String hashAlgorithmName = assertHashAlgorithmName();获取加密算法,md5参数分别是:算法名字:md5 用户输入的密码:0324 盐还是那个截图 散列次数:3为了更直观一点,我又截图了,见下面 重点图1,重点图2,重点图3,重点图4
/* 445 */ return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);见下面具体代码
/* */ }下面是SimpleHash方法:
/* */ public SimpleHash(String algorithmName, Object source, Object salt)
/* */ throws CodecException, UnknownAlgorithmException
/* */ {
/* 139 */ this(algorithmName, source, salt, 1);
/* */ }
/* */ 这里是源码部分,但都是空格我就删除了,大家可以自己debug进去看/* 167 */ if (!(StringUtils.hasText(algorithmName))) {
/* 168 */ throw new NullPointerException("algorithmName argument cannot be null or empty.");
/* */ }
/* 170 */ this.algorithmName = algorithmName;
/* 171 */ this.iterations = Math.max(1, hashIterations);
/* 172 */ ByteSource saltBytes = null;
/* 173 */ if (salt != null) {
/* 174 */ saltBytes = convertSaltToBytes(salt);
/* 175 */ this.salt = saltBytes;
/* */ }
/* 177 */ ByteSource sourceBytes = convertSourceToBytes(source);
/* 178 */ hash(sourceBytes, saltBytes, hashIterations);
/* */ }这一步完毕后,它其实做的就是:
拿用户输入的密码与我们的配置文件的信息来匹配计算,来得到一个加密后的密码这个时候让我们回到上面**********部分代码来看,大家搜索就可以找到,我为方便,把它们粘贴下来:
二、看代码,这里的token和info还是咱们截图的信息
/* */ public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)
/* */ {
/* 379 */ Object tokenHashedCredentials = hashProvidedCredentials(token, info);二A
/* 380 */ Object accountCredentials = getCredentials(info);二B
/* 381 */ return equals(tokenHashedCredentials, accountCredentials);二C
/* */ }我们进入二B来看:它其实就是将我们从数据库查到的暗码拿出来了!
/* */ protected Object getCredentials(AuthenticationInfo info)
/* */ {
/* 345 */ Object credentials = info.getCredentials();
/* *//* 347 */ byte[] storedBytes = toBytes(credentials);
/* *//* 349 */ if ((credentials instanceof String) || (credentials instanceof char[]))
/* *//* */ {
/* 352 */ if (isStoredCredentialsHexEncoded())
/* 353 */ storedBytes = Hex.decode(storedBytes);
/* */ else {
/* 355 */ storedBytes = Base64.decode(storedBytes);
/* */ }
/* */ }
/* 358 */ AbstractHash hash = newHashInstance();
/* 359 */ hash.setBytes(storedBytes);
/* 360 */ return hash;
/* */ }
return equals(tokenHashedCredentials, accountCredentials);二C真正比较开始了,上面我已经详细介绍了 tokenHashedCredentials是如何生成的。这里我们又获取到了数据库的密码,就开始比较了。
由此整个过程结束。
我会将这个代码截图下面,见图密码1,密码2
显然比较结果是错误的。走最初的源码
/* 595 */ CredentialsMatcher cm = getCredentialsMatcher();
/* 596 */ if (cm != null) {
/* 597 */ if (cm.doCredentialsMatch(token, info))
/* */ return;
/* 599 */ String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
/* 600 */ throw new IncorrectCredentialsException(msg);
/* */ }这个时候它就会把密码不正确的异常给出:整个过程我已经描述的很清楚了。
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;@Configuration
@Order(1)
public class ShiroConfiguration {/*** ShiroFilterFactoryBean 处理拦截资源文件问题。* 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在* 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager Filter Chain定义说明* 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过* 3、部分过滤器可指定参数,如perms,roles*/@Beanpublic ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// 必须设置 SecurityManagershiroFilterFactoryBean.setSecurityManager(securityManager);//验证码过滤器Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters();KaptchaFilter kaptchaFilter = new KaptchaFilter();filtersMap.put("kaptchaFilter", kaptchaFilter);//实现自己规则roles,这是为了实现or的效果RoleFilter roleFilter = new RoleFilter();filtersMap.put("roles", roleFilter);shiroFilterFactoryBean.setFilters(filtersMap);// 拦截器.//rest:比如/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。//port:比如/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。//perms:比如/admins/user/**=perms[user:add:*],perms参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,比如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。//roles:比如/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,比如/admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。//要实现or的效果看http://zgzty.blog.163.com/blog/static/83831226201302983358670///anon:比如/admins/**=anon 没有参数,表示可以匿名使用。//authc:比如/admins/user/**=authc表示需要认证才能使用,没有参数//authcBasic:比如/admins/user/**=authcBasic没有参数表示httpBasic认证//ssl:比如/admins/user/**=ssl没有参数,表示安全的url请求,协议为https//user:比如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了filterChainDefinitionMap.put("/logout", "logout");//配置记住我或认证通过可以访问的地址filterChainDefinitionMap.put("/index", "user");filterChainDefinitionMap.put("/", "user");filterChainDefinitionMap.put("/login", "kaptchaFilter");// <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;filterChainDefinitionMap.put("/operation", "roles[admin,aix]");//测试权限页面//这段是配合 actuator框架使用的,配置相应的角色才能访问
// filterChainDefinitionMap.put("/health", "roles[aix]");//服务器健康状况页面
// filterChainDefinitionMap.put("/info", "roles[aix]");//服务器信息页面
// filterChainDefinitionMap.put("/env", "roles[aix]");//应用程序的环境变量
// filterChainDefinitionMap.put("/metrics", "roles[aix]");
// filterChainDefinitionMap.put("/configprops", "roles[aix]");//开放的静态资源filterChainDefinitionMap.put("/favicon.ico", "anon");//网站图标filterChainDefinitionMap.put("/AdminLTE-2.3.7/**", "anon");//配置static文件下资源能被访问的,这是个例子filterChainDefinitionMap.put("/kaptcha.jpg", "anon");//图片验证码(kaptcha框架)filterChainDefinitionMap.put("/**", "authc");// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面shiroFilterFactoryBean.setLoginUrl("/login");// 登录成功后要跳转的链接shiroFilterFactoryBean.setSuccessUrl("/index");// 未授权界面shiroFilterFactoryBean.setUnauthorizedUrl("/errorView/403_error.html");//不生效(详情原因看MyExceptionResolver)shiroFilterFactoryBean.setUnauthorizedUrl("/404");//访问页面,而该角色没有该页面的权限shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}@Beanpublic SecurityManager securityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 设置realm.securityManager.setRealm(myShiroRealm());//注入缓存管理器;//注意:开发时请先关闭,如不关闭热启动会报错//securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;//注入记住我管理器;securityManager.setRememberMeManager(rememberMeManager());return securityManager;}/*** 身份认证realm; (这个需要自己写,账号密码校验;权限等)*/@Beanpublic MyShiroRealm myShiroRealm() {MyShiroRealm myShiroRealm = new MyShiroRealm();myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());return myShiroRealm;}/*** 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了* 所以我们需要修改下doGetAuthenticationInfo中的代码; @return*/@Beanpublic HashedCredentialsMatcher hashedCredentialsMatcher() {HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
// hashedCredentialsMatcher.setHashIterations(2);// 散列的次数,比如散列两次,相当于md5(md5(""));hashedCredentialsMatcher.setHashIterations(3);// 散列的次数,比如散列两次,相当于md5(md5(""));hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);//表示是否存储散列后的密码为16进制,需要和生成密码时的一样,默认是base64;return hashedCredentialsMatcher;}/*** 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;* @param securityManager* @return*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}/*** shiro缓存管理器;* 需要注入对应的其它的实体类中:* 1、安全管理器:securityManager* 可见securityManager是整个shiro的核心;** @return*/@Beanpublic EhCacheManager ehCacheManager(){EhCacheManager cacheManager = new EhCacheManager();cacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");return cacheManager;}/*** cookie对象;* @return* */@Beanpublic SimpleCookie rememberMeCookie(){//System.out.println("ShiroConfiguration.rememberMeCookie()");//这个参数是cookie的名称,对应前端的checkbox的name = rememberMeSimpleCookie simpleCookie = new SimpleCookie("rememberMe");//<!-- 记住我cookie生效时间30天 ,单位秒;-->simpleCookie.setMaxAge(259200);return simpleCookie;}/*** cookie管理对象;* @return*/@Beanpublic CookieRememberMeManager rememberMeManager(){//System.out.println("ShiroConfiguration.rememberMeManager()");CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(rememberMeCookie());return cookieRememberMeManager;}}
shiro加盐走源码相关推荐
- FPGA - Zynq - 加载 - FSBL源码解析1
FPGA - Zynq - 加载 - FSBL源码解析1 前文回顾 FSBL的数据段和代码段如何链接 建个Example工程,不要光顾着看,自己动动手掌握的更快. 查看链接文件,原来存储空间是这样有条 ...
- Android开发之WebView加载HTML源码包含转义字符实现富文本显示的方法
老套路先看效果图: WebView加载带有转移字符的HTML源码 再看转义后的字符的效果图: 先看WebView加载HTML源码的方法如下: webview.loadDataWithBaseURL(n ...
- aes加密php源码,AES加解密类源码 · ThinkPHP5高阶实战教程 --诠释为API开发而生 · 看云...
# AES加解密类源码 > 根据网络整理 ~~~ /** * Created by PhpStorm. * Power by Mikkle * QQ:776329498 * Date: 2017 ...
- Volley 图片加载相关源码解析
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47721631: 本文出自:[张鸿洋的博客] 一 概述 最近在完善图片加载方面的 ...
- 最新图片在线加水印网页源码+亲测可用
正文: 最新图片在线加水印网页源码+亲测可用,专门用于给图片加水印打码的工具,完全基于浏览器本地API,无任何网络请求. 程序: wwuwe.lanzouq.com/i1W4508nyhjc 图片:
- Shiro(三) 身份认证源码分析与 MD5 盐值加密
文章目录 1. 身份认证 2. 身份验证的基本流程 3. 身份验证实现 3.1 在 `login.jsp` 添加登录表单 3.2 添加表单提交的 Controller 3.3 完善 Realm 的身份 ...
- 未能加载文件或程序集rsy3_abp vnext2.0之核心组件模块加载系统源码解析
abp vnext是abp官方在abp的基础之上构建的微服务架构,说实话,看完核心组件源码的时候,很兴奋,整个框架将组件化的细想运用的很好,真的超级解耦.老版整个框架依赖Castle的问题,vnext ...
- Android开发WebView之加载HTML源码修改HTML字体大小以及缩放HTML的方法
老套路上图: 再看下缩放功能: 先说下设置HTML网页字体大小的方法: //设置网页字体大小webview.getSettings().setTextSize(WebSettings.TextSize ...
- abp vnext2.0之核心组件模块加载系统源码解析
abp vnext是abp官方在abp的基础之上构建的微服务架构,说实话,看完核心组件源码的时候,很兴奋,整个框架将组件化的细想运用的很好,真的超级解耦.老版整个框架依赖Castle的问题,vnext ...
- vue 非es6 写法怎么按须加载_Vue源码必学指南:flow(语法检查)以及rollup(模板打包)...
点击上方蓝色字关注我们~ 一.前言 虽然 Vue3 已经公开了代码,但是Vue3.0还处于开发阶段,直接上手使用Typescript是不合适的 , 对于前端的老手是不错的选择, 但是如果没有研究源码经 ...
最新文章
- mysql dump 参数_mysqldump常用参数
- AI用50个三角形画出抽象版蒙娜丽莎,有股后现代的感觉了 | 谷歌大脑出品
- 2011年9月计算机C语言真题,2011年9月全国计算机二级C语言考试真题及答案.doc
- poj-1064Cable master(二分)
- Excel日期函数一览表
- Linux(CentOS)中常用软件安装,使用及异常——XManager, 中文支持,JDK
- PCB设计中焊盘的种类,你都见过几种?
- 移劢开发者解决方案研究报告——中国开发者生存状况调查
- php起点小说小偷程序,PHP小偷程序的简单示例
- Java开发基于控制台的购书系统
- SQL存储过程、存储函数
- 如何搭建视频点播服务
- Java docx4j 操作word 2.1
- sipp命令 各参数含义
- KumiaoQQ机器人框架源码(带成品)
- 使用 Weaviate 矢量搜索为 60 多万篇学术论文构建可扩展的知识图谱搜索
- 一阶电路实验报告心得_一阶rc电路的暂态响应实验报告分析
- Java基础练习--猜数字游戏
- Pycharm 许可证过期解决
- Centos7安装使用libvirt