Shiro入门(1)
=============基本概念===================
什么是Apache Shiro?
Apache Shiro(发音为“shee-roh”,日语“堡垒(Castle)”的意思)是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 - 从命令行应用、移动应用到大型网络及企业应用。
Shiro为解决下列问题(我喜欢称它们为应用安全的四要素)提供了保护应用的API:
认证 - 用户身份识别,常被称为用户“登录”;
授权 - 访问控制;
密码加密 - 保护或隐藏数据防止被偷窥;
会话管理 - 每用户相关的时间敏感的状态。
Shiro还支持一些辅助特性,如Web应用安全、单元测试和多线程,它们的存在强化了上面提到的四个要素。
核心概念:Subject,SecurityManager和Realms
Subject
在考虑应用安全时,你最常问的问题可能是“当前用户是谁?”或“当前用户允许做X吗?”。当我们写代码或设计用户界面时,问自己这些问题很平常:应用通常都是基于用户故事构建的,并且你希望功能描述(和安全)是基于每个用户的。所以,对于我们而言,考虑应用安全的最自然方式就是基于当前用户。Shiro的API用它的Subject概念从根本上体现了这种思考方式。
Subject一词是一个安全术语,其基本意思是“当前的操作用户”。称之为“用户”并不准确,因为“用户”一词通常跟人相关。在安全领域,术语“Subject”可以是人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。
SecurityManager
Subject的“幕后”推手是SecurityManager。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。它是Shiro框架的核心,充当“保护伞”,引用了多个内部嵌套安全组件,它们形成了对象图。但是,一旦SecurityManager及其内部对象图配置好,它就会退居幕后,应用开发人员几乎把他们的所有时间都花在Subject API调用上。
那么,如何设置SecurityManager呢?嗯,这要看应用的环境。例如,Web应用通常会在Web.xml中指定一个Shiro Servlet Filter,这会创建SecurityManager实例,如果你运行的是一个独立应用,你需要用其他配置方式,但有很多配置选项。
一个应用几乎总是只有一个SecurityManager实例。它实际是应用的Singleton(尽管不必是一个静态Singleton)。跟Shiro里的几乎所有组件一样,SecurityManager的缺省实现是POJO,而且可用POJO兼容的任何配置机制进行配置 - 普通的Java代码、Spring XML、YAML、.properties和.ini文件等。基本来讲,能够实例化类和调用JavaBean兼容方法的任何配置形式都可使用。
Realms
Shiro的第三个也是最后一个概念是Realm。Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当切实与像用户帐户这类安全相关数据进行交互,执行认证(登录)和授权(访问控制)时,Shiro会从应用配置的Realm中查找很多内容。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
=======配合Spring的webApp安全管理实验===========
1、创建web工程,导入相应jar包
另外就是spring的包
2、修改web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- Spring配置文件路径 -->
<param-value>classpath*:applicationContext.xml</param-value>
</context-param> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、spring配置文件
<?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-3.2.xsd"> <!-- Shiro Filter 拦截器相关配置 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- securityManager -->
<property name="securityManager" ref="securityManager" />
<!-- 登录路径 -->
<property name="loginUrl" value="/login.jsp" />
<!-- 登录成功后跳转路径 -->
<property name="successUrl" value="/index.jsp" />
<!-- 未登录跳转路径 -->
<property name="unauthorizedUrl" value="/login.jsp" />
<!-- 过滤链定义 -->
<property name="filterChainDefinitions">
<value>
/login.jsp* = anon
/login.do* = anon
/pages/* = authc
/index.jsp* = authc
<!-- 访问这些路径必须拥有某种权限
/role/edit/* = perms[role:edit]
/role/save = perms[role:edit]
/role/list = perms[role:view]
-->
</value>
</property>
</bean> <!-- securityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm" />
</bean>
<!-- 自定义Realm实现 -->
<bean id="myRealm" class="javacommon.shiro.CustomRealm" />
</beans>
过滤链配置了哪些url应该被怎样处理。Shiro内置了不少有用的过滤器:
Anon:不指定过滤器,不错是这个过滤器是空的,什么都没做,跟没有一样。Authc:验证,这些页面必须验证后才能访问,也就是我们说的登录后才能访问。这里还有其他的过滤器,我没用,比如说授权,这个比较重要,但是这个过滤器有个不好的地方,就是要带一个参数,所以如果配在这里就不是很合适,因为每个页面,或是.do的权限不一样,而我们也没法事先知道他需要什么权限。所以这里不配,我们在代码中再授权。这里.do和.jsp后面的*表示参数,比如login.jsp?main这种,是为了匹配这种。
过滤器也可以直接配置,而不使用spring为其提供参数,
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>
org.apache.shiro.web.servlet.IniShiroFilter
</filter-class>
<!-- 没有init-param属性就表示从classpath:shiro.ini装入INI配置 -->
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4、Realm的实现
package javacommon.shiro; 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; public class CustomRealm extends AuthorizingRealm{
/**
* 回调函数,提取当事人的角色和权限
* principals 当事人
*/
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
//用户名
String username = (String) principals.fromRealm(
getName()).iterator().next(); /*这些代码应该是动态从数据库中取出的,此处写死*/
if(username!=null&&username.equals("admin")){
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole("admin");//添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
info.addStringPermission("admin:manage");//添加权限
return info;
}
return null;
} /**
* 登录验证
*/
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authcToken ) throws AuthenticationException {
//令牌——基于用户名和密码的令牌
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
//令牌中可以取出用户名密码
String accountName = token.getUsername(); /*此处无需比对,比对的逻辑Shiro会做,我们只需返回一个和令牌相关的正确的验证信息,因此在随后的登录页面上只有admin/admin123才能通过验证*/
return new SimpleAuthenticationInfo("admin","admin123",getName());
} }
5、处理登录
/login.jsp:
<body>
<h3>${msg }</h3>
<form action="LoginServlet" method="post">
<br />用户帐号: <input type="text" name="username" id="username" value="" />
<br />登录密码: <input type="password" name="password" id="password"
value="" /> <br />
<input value="登录" type="submit">
</form>
</body>
LoginServlet代码片段:
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//当前Subject
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(
request.getParameter("username"),
request.getParameter("password"));
token.setRememberMe(true);
try {
/*
* 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm
* ,执行必须的认证检查。每个Realm都能在必要时对提交的AuthenticationTokens作出反应。
* 但是如果登录失败了会发生什么?如果用户提供了错误密码又会发生什么?通过对Shiro的运行时AuthenticationException做出反应
* ,你可以控制失败
*/
currentUser.login(token);
request.getRequestDispatcher("/index.jsp").forward(request,
response);
} catch (AuthenticationException e) {//登录失败
e.printStackTrace();
request.setAttribute("msg", "不匹配的用户名和密码");
request.getRequestDispatcher("/login.jsp").forward(request,
response);
}
}
6、测试
直接访问/pages/**.jsp,因为这个是需要认证才能访问的页面,所以,直接访问会被转发到登录页面。
登录页面输入正确的用户名/密码,将按照LoginServlet的流程来走。
登录成功后,同一个会话再去访问那些被保护的页面或资源不需重复登录。
待解决问题:
权限的判断;
加密;
Shiro入门(1)的更多相关文章
- Apache shiro集群实现 (一) shiro入门介绍
近期在ITOO项目中研究使用Apache shiro集群中要解决的两个问题,一个是Session的共享问题,一个是授权信息的cache共享问题,官网上给的例子是Ehcache的实现,在配置说明上不算很 ...
- 用户认证授权和Shiro入门
1.权限管理基础(认证和授权): 前言 本文主要讲解的知识点有以下: 权限管理的基础知识 模型 粗粒度和细粒度的概念 回顾URL拦截的实现 Shiro的介绍与简单入门 一.Shiro基础知识 在学习S ...
- shiro入门教程
一.shiro入门 shiro.ini和log4j.properties要放在src下面,lib是和src同级别的,然后lib下面的jar包是必须的,lib下面的jar包需要add path,如果报错 ...
- 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权
原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...
- Shiro入门指引
最近项目中用到Shiro,专门对其研究了一番,颇有收获,以下是笔者最近写的博客,希望对大家入门有所帮助. Shiro入门资源整理 Shiro在SpringBoot中的使用 Shiro源码解析-登录篇 ...
- Shiro——入门Demo
Shiro——入门Demo 环境- 引入相关maven依赖, shiro-core,commons-logging 配置shiro配置文件:ini后缀 主方法测试: import org.apach ...
- Shiro入门学习之shi.ini实现授权(三)
一.Shiro授权 前提:需要认证通过才会有授权一说 1.授权过程 2.相关方法说明 ①subject.hasRole("role1"):判断是否有该角色 ②subject.has ...
- Shiro入门学习与实战(一)
一.概述 1.Shiro是什么? Apache Shiro是java 的一个安全框架,主要提供:认证.授权.加密.会话管理.与Web集成.缓存等功能,其不依赖于Spring即可使用: Spring S ...
- shiro入门学习--使用MD5和salt进行加密|练气后期
写在前面 在上一篇文章<Shiro入门学习---使用自定义Realm完成认证|练气中期>当中,我们学会了使用自定义Realm实现shiro数据源的切换,我们可以切换成从关系数据库如MySQ ...
- 安全框架Shiro入门
Shiro简介 Apache Shiro是Java的一个安全框架,官网为shiro.apache.org,主要场景为控制登陆,判断用户是否有访问某个功能的权限等等. Shiro的核心功能(入门知识,只 ...
随机推荐
- 在MySQL中创建实现自增的序列(Sequence)的教程
这篇文章主要介绍了在MySQL中创建实现自增的序列(Sequence)的教程,分别列举了两个实例并简单讨论了一些限制因素,需要的朋友可以参考下 项目应用中,曾有以下一个场景: 接口中要求发送一个int ...
- java中如何计算两个时间段的月份差
直接计算,先取得两个日期的年份和月份,月份差=(第二年份-第一年份)*12 + 第二月份-第一月份
- (转)Log4J日志配置详解
http://www.cnblogs.com/ITtangtang/p/3926665.html 一.Log4j简介 Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源 ...
- android 自定义百度地图放大缩小
自定义实现Android百度地图的缩放图标,需要自定义一个缩放控件,实现效果如下: 这里的缩放效果,实现了点击按钮可以对地图的放大缩小,通过手势放大与缩小也控制缩放图标的可用状态.具体实现如下: zo ...
- Windows Azure 即将更名
今天我们宣布自2014 年4 月3 日起,WindowsAzure 将更名为Microsoft Azure.这一更名反映了Microsoft 的战略,并显示了Microsoft 专注于将Azur ...
- WeasyPrint - Converts HTML + CSS to PDF - WeasyPrint converts HTML/CSS documents to PDF
WeasyPrint - Converts HTML + CSS to PDF - WeasyPrint converts HTML/CSS documents to PDF WeasyPrint c ...
- java 解析国密SM2算法证书
首先说明用Java自带的解析x509证书类,是不能解析sm2算法的证书,执行会抛出异常. 用开源库bouncycastle能够解析.详细代码 private byte[] getCSPK(byte[] ...
- Android学习笔记(十五)——碎片的生命周期(附源代码)
碎片的生命周期 点击下载源代码 与活动类似.碎片具有自己的生命周期.理解了碎片的生命周期后.我们能够在碎片被销毁时正确地保存事实上例,在碎片被重建时将其还原到前一个状态. 1.使用上一篇的项目Frag ...
- 2.4.5 用NPOI操作EXCEL--插入图片
我们知道,在Excel中是可以插入图片的.操作菜单是“插入->图片”,然后选择要插入图片,可以很容易地在Excel插入图片.同样,在NPOI中,利用代码也可以实现同样的效果.在NPOI中插入图片 ...
- iOS获取运营商信号强度
此API是apple私有API,所以只可运用在越狱设备中,如果提交appstore,会遭遇apple的拒绝上架反馈! #import <dlfcn.h> int getSignalLeve ...