SSH入门项目-6-Shiro安全框架
Shiro安全框架
百度一下:
Apache Shiro(读作“sheeroh”,即日语“城”)是一个开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。
- Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
- Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
- Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
- Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Shiro安全框架交互过程:
- Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;
- SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;
- Realm:域,Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
程序员关注2个部分:如果获得Subject与如何定义一个符合规定的Realm(包括密码比较器)。
Shiro安全框架过滤器配置:
过滤器简称 | 对应的java类 |
---|---|
anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port | org.apache.shiro.web.filter.authz.PortFilter |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
ssl | org.apache.shiro.web.filter.authz.SslFilter |
user | org.apache.shiro.web.filter.authc.UserFilter |
logout | org.apache.shiro.web.filter.authc.LogoutFilter |
Shiro标签:
标签名称 | 标签条件(均是显示标签内容) |
---|---|
shiro:authenticated | 登录之后 |
shiro:notAuthenticated | 不在登录状态时 |
shiro:guest | 用户在没有RememberMe时 |
shiro:user | 用户在RememberMe时 |
shiro:hasAnyRoles name=”abc,123” | 在有abc或者123角色时 |
shiro:hasRole name=”abc” | 拥有角色abc |
shiro:lacksRole name=”abc” | 没有角色abc |
shiro:hasPermission name=”abc” | 拥有权限资源abc |
shiro:lacksPermission name=”abc” | 没有abc权限资源 |
shiro:principal | 默认显示用户名称 |
使用Shiro
1,maven坐标的配置
在parent的工程中已经配置好了。
2,配置过滤器(放到struts的配置之前)
<filter><filter-name>shiroFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><init-param><param-name>targetFilterLifecycle</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
3,在spring applicationContext.xml中记载shiro配置文件,放在事务管理器之前配置
这里就是产生代理的方式,应该放在事务代理器之前
<!--2.Shiro安全框架产生代理子类的方式: 使用cglib方式 --><aop:aspectj-autoproxy proxy-target-class="true" />
4,导入Shiro的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><description>Shiro的配置</description><!-- SecurityManager配置 --><!-- 配置Realm域 --><!-- 密码比较器 --><!-- 代理如何生成? 用工厂来生成Shiro的相关过滤器--><!-- 配置缓存:ehcache缓存 --><!-- 安全管理 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><!-- Single realm app. If you have multiple realms, use the 'realms' property instead. --><property name="realm" ref="authRealm"/><!-- 引用自定义的realm --><!-- 缓存 --><property name="cacheManager" ref="shiroEhcacheManager"/></bean><!-- 自定义权限认证 --><bean id="authRealm" class="cn.itcast.jk.shiro.AuthRealm"><property name="userService" ref="userService"/><!-- 自定义密码加密算法 --><property name="credentialsMatcher" ref="passwordMatcher"/></bean><!-- 设置密码加密策略 md5hash --><bean id="passwordMatcher" class="cn.itcast.jk.shiro.CustomCredentialsMatcher"/><!-- filter-name这个名字的值来自于web.xml中filter的名字 --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager"/><!--登录页面 --><property name="loginUrl" value="/index.jsp"></property><!-- 登录成功后 --> <property name="successUrl" value="/home.action"></property><property name="filterChainDefinitions"><!-- /**代表下面的多级目录也过滤 --><value>/index.jsp* = anon/home* = anon/sysadmin/login/login.jsp* = anon/sysadmin/login/logout.jsp* = anon/login* = anon/logout* = anon/components/** = anon/css/** = anon/images/** = anon/js/** = anon/make/** = anon/skin/** = anon/stat/** = anon/ufiles/** = anon/validator/** = anon/resource/** = anon/** = authc/*.* = authc</value></property></bean><!-- 用户授权/认证信息Cache, 采用EhCache 缓存 --><bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/></bean><!-- 保证实现了Shiro内部lifecycle函数的bean执行 --><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!-- 生成代理,通过代理进行控制 --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor"><property name="proxyTargetClass" value="true"/></bean><!-- 安全管理器 --><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager"/></bean></beans>
做一点简单的描述吧。
在shiro的配置文件中,需要我我们手动处理的几个部分。
安全管理器的配置
需要注入我们自己的验证域和一个缓存管理。缓存管理比较简单,验证域应该就是我们比较和新的验证业务。
缓存管理的内容如下,这个路径是需要我们手动更改的。
自定义的认证域配置
我们需要注入一个是用户的service,另一个是我们的密码比较器。
我们看到出了注入下方的bean就是我们自定义的密码比较器。
5,先配置一些必要的注入等内容:
5.1,先导入缓存管理的文件
我们之前看到上图中的缓存管理注入的位置是“classpath:ehcache-shiro.xml”,所以我们就在resource中直接创建这个文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shiroCache"><defaultCache
maxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="false"diskPersistent="false"diskExpiryThreadIntervalSeconds="120"/>
</ehcach
5.2,密码比较器
先用一个密码比较器的空模板,包的位置看一下注入的property
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {public boolean doCredentialsMatch(AuthenticationToken token,AuthenticationInfo info) {return false;}
}
5.3,AuthRealm的注入set方法。
public class AuthRealm extends AuthorizingRealm{public UserService userService;public void setUserService(UserService userService) {this.userService = userService;}//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {// TODO Auto-generated method stubreturn null;}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {// TODO Auto-generated method stubreturn null;}}
6,在Spring中导入Shiro的配置文件
<import resource="classpath:applicationContext-shiro.xml"></import>
运行起来之后,点击部门管理会变成下面这个死样子
原因就是部门管理不能直接访问了,需要转到登录页,但是我们的系统目前没有登录功能,就只能回到这个首页了。
很难得,一个错误的页面验证了之前的工作都是正确的。保存一下草稿,丢了N回了。
解决一下,在fmain.jsp中添加一个script
<script type="text/javascript">if (self.location != top.location) {top.location = self.location;}
</script>
解释一下,由于shiro过滤器告诉失败会让我们的页面回到index.jsp,而我们顶层框架是部门管理。于是我们通过上述代码让顶层框架访问index.jsp。其原因是我们现在没有配合登录页面。
于是我们回到LoginAction类中,看到我们之前注释掉的代码,做一点修改。
public String login() throws Exception {// if(true){// String msg = "登录错误,请重新填写用户名密码!";// this.addActionError(msg);// throw new Exception(msg);// }// User user = new User(username, password);// User login = userService.login(user);// if (login != null) {// ActionContext.getContext().getValueStack().push(user);// session.put(SysConstant.CURRENT_USER_INFO, login); //记录session// return SUCCESS;// }// return "login";if (UtilFuns.isEmpty(username)) {return "login";}return SUCCESS;}
再看一下。
7,补充登录功能
7.1,密码比较器编写
7.1.1,导入md5hash工具类
在util中添加Encrypt工具类。
public class Encrypt {/** 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,* 常见的散列算法如MD5、SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,* 产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,* 可以到一些md5解密网站很容易的通过散列值得到密码“admin”,* 即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,* 如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。*///高强度加密算法,不可逆public static String md5(String password, String salt){return new Md5Hash(password,salt,2).toString();}
}
7.1.2,密码比较器的编写
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {// token:用户在页面输入的用户名密码,info代表从密码中得到的加数据public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {// 向下转型UsernamePasswordToken usertoken = (UsernamePasswordToken) token;// 将用户输入的原始密码加密// 注意token.getPassword()拿到的是一个char[],不能直接用toString(),它底层实现不是我们想的直接字符串,只能强转// 用户名做为saltObject tokenCredentials = Encrypt.md5(String.valueOf(usertoken.getPassword()), usertoken.getUsername());//取得数据库中的密码数据Object accountCredentials = getCredentials(info);return equals(tokenCredentials, accountCredentials);}}
这里的使用的equals是父类提供的。
7.2,认证域的编写
package com.liuyang19900520.liussh.shiro;import java.util.ArrayList;
import java.util.List;
import java.util.Set;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.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;import com.liuyang19900520.liussh.domain.Module;
import com.liuyang19900520.liussh.domain.Role;
import com.liuyang19900520.liussh.domain.User;
import com.liuyang19900520.liussh.service.UserService;public class AuthRealm extends AuthorizingRealm {// 注入public UserService userService;public void setUserService(UserService userService) {this.userService = userService;}// 授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {System.out.println("授权");// 首先根据name找到对象,对象的next就是一个userUser user = (User) arg0.fromRealm(this.getName()).iterator().next();// 根据realm的名字去找对应的realm。Set<Role> roles = user.getRoles();// 兑现导航List<String> permissions = new ArrayList<>();for (Role role : roles) {Set<Module> moudles = role.getModules();for (Module m : moudles) {// 这些标签在shiro:hasPermission的标签中会出现重复,// 但是标签的操作时用hascontents方法来进行,所以有重复也没有关系permissions.add(m.getName());}}SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.addStringPermissions(permissions);// 添加用户的权限--即我们的模块return info;}// 认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {System.out.println("认证");// 向下转型(代表用户用在页面上输入的用户名与密码)UsernamePasswordToken upToken = (UsernamePasswordToken) arg0;// 调用业务方法,根据业务名查询String hql = "from User where userName=?";List<User> list = userService.find(hql, User.class, new String[] { upToken.getUsername() });if (list != null && list.size() > 0) {User user = list.get(0);AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassWord(), this.getName());return info;// 此处如果返回,就会进入到密码比较器。}return null;}}
7.3,编写loginAction写登录逻辑
// SSH传统登录方式public String login() throws Exception {if (UtilFuns.isEmpty(username)) {return "login";}try {// 得到SubjectSubject subject = SecurityUtils.getSubject();// 构造token(我们的username和password是页面上的)UsernamePasswordToken upToken = new UsernamePasswordToken(username, password);// 盗用shiro中的登录方法subject.login(upToken);// 当这一行代码执行时,就会自动跳转到比吗比较器// shiro有缓存,用户信息存在缓存中,User user = (User) subject.getPrincipal();// 将User放入sessoin中session.put(SysConstant.CURRENT_USER_INFO, user);} catch (Exception e) {request.put("errorInfo", "对不起,用户名密码错误");return "login";}return SUCCESS;}
8,顶部菜单释放
如果你也想问,为什么左侧的菜单不用加shiro标签么,那么请看一下左侧菜单的代码。
如图所示也就是说我们后续进到的模块都是通过user的角色到数据库查询出来的,不在需要shiro标签进行授权了,就是说菜单都是动态的。
所以我们要解开这个
还有值得注意的一点是,一旦JSP页面上出现shiro标签,就会执行授权方法。即认证域中的doGetAuthorizationInfo方法。
日常改错
输入正确的用户密码都不好使啊。这下验证得实在是太好了。
于是我重启了一下服务,JRbel真的不好使啊。于是成功了。
虽然权限看起来不同了,可是菜单怎么突然变多了这么多,并且还是重复的,一定是哪里出了问题。我们再来查询一下。
结果是清一下浏览器缓存,应该就没有问题了。
SSH入门项目-6-Shiro安全框架相关推荐
- Shiro安全框架【快速入门】就这一篇!
Shiro 简介 照例又去官网扒了扒介绍: Apache Shiro™ is a powerful and easy-to-use Java security framework that perfo ...
- (转) shiro权限框架详解06-shiro与web项目整合(上)
http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springM ...
- 视频教程-Apache Shiro权限框架实战+项目案例视频课程-Java
Apache Shiro权限框架实战+项目案例视频课程 拥有10余年项目实战经验. 2006-2011在nttdata从事对日软件开发类工作. 2011-2015在HP从事技术服务工作. 擅长于j2e ...
- Shiro安全框架【SpringBoot版】
文章目录 Shiro安全框架 一. 入门概述 1.1.Shiro是什么 1.2.为什么使用Shiro 1.3.Shiro与Spring Security的区别 1.4.基本功能 1.4.1.主要功能 ...
- 在Spring MVC中使用Apache Shiro安全框架
我们在这里将对一个集成了Spring MVC+Hibernate+Apache Shiro的项目进行了一个简单说明.这个项目将展示如何在Spring MVC 中使用Apache Shiro来构建我们的 ...
- 基于Springboot2.0的Dubbo入门项目(dubbo-spring-boot-starter)
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成.最近半年来,Dubbo的得到了快速的维护,官方也推出了 ...
- shiro subject.getprincipal()为null_(变强、变秃)Java从零开始之Shiro安全框架
Shiro安全框架 一.Shiro简介 二.Shiro架构图 三.Shiro涉及常见名词 四.Shiro配置文件详解 shiro.ini 文件放在 classpath 下 ,shiro 会自动查找.其 ...
- thymeleaf模板引擎shiro集成框架
shiro权限框架.前端验证jsp设计.间tag它只能用于jsp系列模板引擎. 使用最近项目thymeleaf作为前端模板引擎,采用HTML档,未出台shiro的tag lib,假设你想利用这段时间s ...
- idea怎么运行eclipse的web项目_Apache Storm v2.0入门项目的开发、测试和运行(IDEA/Maven)...
第一个Apache Storm v2.0流计算入门项目的开发.测试和运行(IDEA/Maven) 关于流计算框架Apache Storm最新版的安装,可以参考: 流计算框架-最新版Apache Sto ...
最新文章
- 关于BIO | NIO | AIO的讨论
- python字典操作添加_Python字典常见操作实例小结【定义、添加、删除、遍历】
- 2020-08-20如何获取AWS的Access Key ID 和 Secret Access Key (Unable to find credentials)
- 使用IB_DESIGNABLE与IBInspectable特性实现可在视图编辑器的功能栏中设置
- 09-spring学习-资源访问接口
- Openvswitch手册(5): VLAN and Bonding
- 【学习笔记】37、用正则表达式解析和提取数据
- ArcGIS 空间查询一例
- python中sign函数图片_python接口自动化-实现sign签名(MD5加密)
- 如何为 .NET Core 3.0 中 WPF 配置依赖注入 ?
- Qt线程和signal-slot
- NOIp 2014 联合权值 By cellur925
- Google 最高级别工程师的教育梦
- 洗清UI自动化鸡肋说的不白之冤
- JAVA_JDK下载与安装教程
- 2021年山东省安全员C证考试及山东省安全员C证模拟考试
- (转)iOS开发-常用第三方开源框架介绍(你了解的ios只是冰山一角)
- java 读取excel模板_java如何读取excel表格的信息,java读取excel模板
- 天融信防火墙tcpdump
- 阿里云机器学习平台PAI的视频介绍(其中tensorflow高级教程有tf的代码优化讲解)
热门文章
- VINS-Mono之IMU预积分,预积分误差、协方差及误差对状态量雅克比矩阵的递推方程的推导
- 大型数据库复习笔记——PL/SQL
- llt自发光_X射线激发荧光光谱仪的建立及闪烁晶体发光表征
- 如果客户只给我5分钟时间介绍EWM,怎么办?
- 解决Qt5.8加载qt_zh_CN.qm之后QMessageBox仍显示英文的问题
- springMVC数据校验
- CAN收发器PCA82C251与TJA1040的异同
- 区块链的梦该醒了吗?不,他们依然在想着感恩世界
- TCL通讯第三季度智能手机和平板电脑出货量显著增长;亚马逊云科技加速数据库服务在中国区域落地 | 全球TMT...
- 2022年第十一届认证杯数学中国数学建模国际赛小美赛:D题野生动物贸易是否应该长期禁止建模方案及代码实现