Shiro单Realm加密
首先,我们要明确认证的流程:
1. 获取当前的 Subject. 调用 SecurityUtils.getSubject();
2. 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated()
3. 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
1). 创建一个表单页面
2). 把请求提交到 SpringMVC 的 Handler
3). 获取用户名和密码.
4. 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法.
5. 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.
1). 实际上需要继承 org.apache.shiro.realm.AuthenticatingRealm 类
2). 实现 doGetAuthenticationInfo(AuthenticationToken) 方法.
6. 由 shiro 完成对密码的比对..
密码的比对:
通过 AuthenticatingRealm 的 credentialsMatcher 属性来进行的密码的比对!
如何把一个字符串加密为 MD5
替换当前 Realm 的 credentialsMatcher 属性. 直接使用 HashedCredentialsMatcher 对象, 并设置加密算法即可.
为什么使用 MD5 盐值加密?如何做到?
如何做到:
1). 在 doGetAuthenticationInfo 方法返回值创建 SimpleAuthenticationInfo 对象的时候, 需要使用
SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName) 构造器
2). 使用 ByteSource.Util.bytes() 来计算盐值.
3). 盐值需要唯一: 一般使用随机字符串或 user id
4). 使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 来计算盐值加密后的密码的值.
接下来,我们进行代码的编写和配置文件的相关配置
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- =========================================================
Shiro Core Components - Not Spring Specific
========================================================= -->
<!-- Shiro's main business-tier object for web-enabled applications
(use DefaultSecurityManager instead when there is no web environment)-->
<!--
1.配置SecurityManager!
-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<property name="realm" ref="jdbcRealm"/>
</bean> <!-- Let's use some enterprise caching support for better performance. You can replace this with any enterprise
caching framework implementation that you like (Terracotta+Ehcache, Coherence, GigaSpaces, etc --> <!--
2.配置cacheManager
2.1 需要加入ehcache的jar包及配置文件
-->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<!-- Set a net.sf.ehcache.CacheManager instance here if you already have one. If not, a new one
will be creaed with a default config:
<property name="cacheManager" ref="ehCacheManager"/> -->
<!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance to inject, but you want
a specific Ehcache configuration to be used, specify that here. If you don't, a default
will be used.: -->
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean> <!-- Used by the SecurityManager to access security data (users, roles, etc).
Many other realm implementations can be used too (PropertiesRealm,
LdapRealm, etc. --> <!--
3.配置Realm
3.1直接配置实现了com.atguigu.shiro.realms.ShiroRealm接口的bean
-->
<bean id="jdbcRealm" class="com.atguigu.shiro.realms.ShiroRealm">
<!-- 配置MD5加密 -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 指定加密方式为MD5 -->
<property name="hashAlgorithmName" value="MD5"></property>
<!-- 指定加密次数 -->
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean> <!-- =========================================================
Shiro Spring-specific integration
========================================================= -->
<!-- Post processor that automatically invokes init() and destroy() methods
for Spring-configured Shiro objects so you don't have to
1) specify an init-method and destroy-method attributes for every bean
definition and
2) even know which Shiro objects require these methods to be
called. -->
<!--
4.配置LifecycleBeanPostProcessor,可以自动地来调用配置在Spring IOC容器中shiro bean的生命周期方法
-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- Enable Shiro Annotations for Spring-configured beans. Only run after
the lifecycleBeanProcessor has run: --> <!--
5.启用IOC容器中使用shiro的注解,但必须在配置了LifecycleBeanPostProcessor之后才可以使用
-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean> <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -
web.xml uses the DelegatingFilterProxy to access this bean. This allows us
to wire things with more control as well utilize nice Spring things such as
PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: --> <!--
6.配置ShiroFilter
6.1 id必须和web.xml文件中配置的DelegatingFilterProxy的 <filter-name> 一致
若不一致,则会抛出:NoSuchBeanDefinitionException. 因为 Shiro 会来 IOC 容器中查找和 <filter-name> 名字对应的 filter bean.
6.2
-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login.jsp"/>
<property name="successUrl" value="/list.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/> <!--
配置哪些页面需要受保护
以及访问这些页面需要的权限
1). anon 可以被匿名访问
2). authc 必须认证(即登录)后才可以访问的页面
3). logout 登出
-->
<property name="filterChainDefinitions">
<value>
/login.jsp = anon
/shiro/login = anon
/shiro/logout = logout
# everything else requires authentication:
/** = authc
</value>
</property>
</bean>
</beans>
ShiroHandler.java
package com.atguigu.shiro.handlers; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
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 org.springframework.web.bind.annotation.RequestParam; @Controller
@RequestMapping("/shiro")
public class ShiroHandler { @RequestMapping("/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
// 获取当前的 Subject. 调用 SecurityUtils.getSubject();
Subject currentUser = SecurityUtils.getSubject();
// 测试当前的用户是否已经被认证. 即是否已经登录.
// 调动 Subject 的 isAuthenticated()
if (!currentUser.isAuthenticated()) {
// 把用户名和密码封装为 UsernamePasswordToken 对象
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
// rememberme
token.setRememberMe(true);
try {
System.out.println("1." + token.hashCode());
// 执行登录.
currentUser.login(token);
}
// 所有认证时异常的父类.
catch (AuthenticationException ae) {
System.out.println("登录失败:"+ae.getMessage());
}
}
return "redirect:/list.jsp";
}
}
ShiroRealm.java
package com.atguigu.shiro.realms; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource; public class ShiroRealm extends AuthenticatingRealm { @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("doGetAuthenticationInfo " + token.hashCode()); //1. 把AuthenticationToken 转换为 UsernamePasswordToken
UsernamePasswordToken upToken = (UsernamePasswordToken)token; //2. 从UsernamePasswordToken 中来获取username
String username = upToken.getUsername(); //3.调用数据库的方法,从数据库查询username 对应的用户记录
System.out.println("从数据库中获取username:" + username +" 所对应的用户信息"); //4.若用户不存在可以抛出 UnknownAccountException 异常
if ("unknown".equals(username)) {
throw new UnknownAccountException("用户不存在");
} //5.根据用户信息的情况,决定是否抛出其它的 AuthenticationException 异常
if ("monster".equals(username)) {
throw new LockedAccountException("用户被锁定");
} //6.根据用户的情况,来构建 AuthenticationToken 对象并返回,通常使用的实现类为:SimpleAuthenticationInfo
//一下信息是从数据库中获取的
//1).principals:认证的实体信息,可以是username,也可以是数据表对应的实体类对象
Object principal = username;
//2).credentials:密码
Object hashedCredentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4";
if ("admin".equals(username)) {
hashedCredentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
}else if("user".equals(username)) {
hashedCredentials = "098d2c478e9c11555ce2823231e02ec1";
} //3).realmName:当前realm 对象的name,调用父类的getName()方法即可
String realmName = getName();
//4).盐值
//SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credential,realmName);
//因为用户名唯一,使用用户名作为盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(username);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realmName);
return info;
} public static void main(String[] args) {
String algorithmName = "MD5";
Object password = "123456";
Object salt = ByteSource.Util.bytes("user");
int hashIterations = 1024;
Object result = new SimpleHash(algorithmName, password, salt, hashIterations);
System.out.println(result);
} }
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" dynamicConfig="false">
<diskStore path="java.io.tmpdir"/>
<!--授权信息缓存-->
<cache name="authorizationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache>
<!--身份信息缓存-->
<cache name="authenticationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache>
<!--session缓存-->
<cache name="activeSessionCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache> <!-- 缓存半小时 -->
<cache name="halfHour"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
diskPersistent="false" /> <!-- 缓存一小时 -->
<cache name="hour"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="false"
diskPersistent="false" /> <!-- 缓存一天 -->
<cache name="oneDay"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="86400"
timeToLiveSeconds="86400"
overflowToDisk="false"
diskPersistent="false" /> <!--
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<defaultCache name="defaultCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="600"
overflowToDisk="false"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/> </ehcache>
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4>Login Page</h4>
<form action="shiro/login" method="post">
username:<input type="text" name="username"/>
<br/><br/>
password:<input type="password" name="password"/>
<br/><br/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
Shiro单Realm加密的更多相关文章
- Shiro笔记(四)Shiro的realm认证
认证流程: 1.获取当前Subject.调用SecurityUtils.getSubject(); 2.测试当前用户是否已经被认证,即是否已经登录,调用Subject的isAurhenticated( ...
- shiro教程3(加密)
加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容 概念 数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理, ...
- shiro双realm验证
假设现在有这样一种需求:存在两张表user和admin,分别记录普通用户和管理员的信息.并且现在要实现普通用户和管理员的分开登录,即需要两个Realm——UserRealm和AdminRealm,分别 ...
- shiro多realm验证之——shiro实现不同身份使用不同Realm进行验证(转)
转自: http://blog.csdn.net/xiangwanpeng/article/details/54802509 (使用特定的realm实现特定的验证) 假设现在有这样一种需求:存在两张表 ...
- Shiro多Realm验证
在单Realm的基础上,进行如下内容的修改 原有的ShiroRealm.java: package com.atguigu.shiro.realms; import org.apache.shiro. ...
- Shiro中Realm
6.1 Realm [2.5 Realm]及[3.5 Authorizer]部分都已经详细介绍过Realm了,接下来再来看一下一般真实环境下的Realm如何实现. 1.定义实体及关系 即用户-角色 ...
- springboot shiro 多realm配置认证、授权
shiro进行登录认证和权限管理的实现.其中需求涉及使用两个角色分别是:门店,公司.现在要两者实现分开登录.即需要两个Realm——MyShiroRealmSHOP和MyShiroRealmCOMPA ...
- shiro盐值加密并验证
在数据表中存的密码不应该是123456,而应该是123456加密之后的字符串,而且还要求这个加密算法是不可逆的,即由加密后的字符串不能反推回来原来的密码,如果能反推回来那这个加密是没有意义的.著名的加 ...
- shiro自定义Realm
1.1 自定义Realm 上边的程序使用的是shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm. ...
随机推荐
- LeetCode 14. 最长公共前缀(Longest Common Prefix)
题目描述 编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow ...
- Postman下载与安装
融e学-一个专注于重构知识,培养复合型人才的平台:http://www.i-ronge.com/ Postman 的官网下载地址是:https://www.getpostman.com/ 下载后看到压 ...
- Edge Detection
Edge Detection Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22604 Accepted: 5311 ...
- 阶段3 2.Spring_01.Spring框架简介_06.spring的体系结构
资料内提供了spring 的开发包 docs:文档 libs:jar包 schema:约束
- iOS多选实现注意点
下面对APP的多选选择列表实现进行总结,为了在以后的每个项目的多选实现,测试总是提一样的bug总结的. 具体的实现代码就不复制粘贴了,不过在多选问题上遇到问题的可以我们一起讨论讨论的哈... 可能总结 ...
- Activity启动模式分类(一)
standerd 默认模式,每次启动Activity都会创建一个新的Activity实例. 比如:现在有个A Activity,我们在A上面启动B,再然后在B上面启动A,其过程如图所示: single ...
- Linux进程的虚拟内存
简介 用户进程的虚拟地址空间是Linux的一个重要的抽象:它为每个运行进程提供了同样的系统视图,这使得多个进程可以同时运行,而不会干扰到其他进程内存中的内容. 每个应用程序都有自己的线性地址空间,与所 ...
- json,异步加载,时间线
JSON是一种传输数据的格式 JSON.stringify(obj); obj--string JSON.parse(str); string-->obj
- 手写朴素贝叶斯(naive_bayes)分类算法
朴素贝叶斯假设各属性间相互独立,直接从已有样本中计算各种概率,以贝叶斯方程推导出预测样本的分类. 为了处理预测时样本的(类别,属性值)对未在训练样本出现,从而导致概率为0的情况,使用拉普拉斯修正(假设 ...
- 【VS开发】Windows上的音频采集技术
前一段时间接到一个任务,需要采集到声卡的输出信号,以便与麦克风的输入信号进行混音. 之前一直没有研究过音频的相关技术,这次就顺便抽出一点时间去了解了一下Windows上采集音频的相关技术. 对于音频处 ...