Shiro 的简介
A、 为什么学习 Shiro
目前使用遇到的问题?
[1]使用 RBAC 进行角色访问控制的时候,代码书写起来相对 比较麻烦
[2]目前学习的写的操作代码整体不太安全
B、解决的方案
[1]Spring securing 安全框架 缺点:基于 Spring 之上 的,局限性比较大
[2]shiro javaEE javaSE 分布式项目
C、 什么是 shiro
Apache Shiro 是一个强大而灵活的开源安全框架,它干净利 落地处理身份认证,授权,企业会话管理和加密
Shiro 的官网: http://shiro.apache.org/
D、 Shiro 中的体系的组成
Authentication:身份的验证-就是我们平时做的登录
Authorization:授权:赋予角色不同的 菜单功能
Session Management:管理登录用户的信息
Cryptography:加密技术 MD5 加密算法等。。
Web Support:shiro 对 web 项目进行的支持
Caching:缓存 可以安全快速的操作
Concurrency:支持并发多线程的处理
Testing:测试
Run As:可以实现在一个用户允许的前提下,使用另一 个用户访问
Remember Me:记住我
E、 shiro 的架构
Subject
(org.apache.shiro.subject.Subject)当前与软 件进行交互的实体(用户,第三方服务,cron job,等 等)的安全特定“视图”
SecurityManager
:SecurityManager 是 Shiro 架构的 心脏。它基本上是一个“保护伞”对象,协调其管理的组 件 以 确 保 它 们 能 够 一 起 顺 利 的 工 作 类 似 于 SpringMVC 中的入口 servlet
Realms
:域 Realms 在 Shiro 和你的应用程序的安全数据之间担当 “桥梁”或“连接器”。当它实际上与安全相关的数据如用来执行身份验证(登录)及授权(访问控制)的用户帐 户交互时,Shiro 从一个或多个为应用程序配置的 Realm 中寻找许多这样的东西
Shiro 的环境搭建
使用 shiro 实现登陆的操作
第一步 导包
第二步:书写shiro.ini
文件
[users]
zs=123
sxt=root
第三步:书写测试代码
package com.bjsxt.shiro1;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.apache.shiro.mgt.SecurityManager;
public class TestA {
public static void main(String[] args) {
//[1]解析shiro.ini文件
Factory<SecurityManager> factory =new IniSecurityManagerFactory("classpath:shiro.ini");
//[2]通过SecurityManager工厂获得SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//[3]把SecurityManager对象设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//[4]通过SecurityUtils获得主体subject
Subject subject = SecurityUtils.getSubject();
//[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
//我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
UsernamePasswordToken token =new UsernamePasswordToken("zs","123");
try {
//[6]进行身份的验证
subject.login(token);
//[7]通过方法判断是否登录成功
if(subject.isAuthenticated()){
System.out.println("登录成功");
}
} catch (IncorrectCredentialsException e) {
System.out.println("登录失败");
}catch (UnknownAccountException e){
System.out.println("用户名不正确");
}
}
}
Shiro 验证时异常分析
账户失效异常
DisabledAccountException
竞争次数过多
ConcurrentAccessException
尝试次数过多
ExcessiveAttemptsException
用户名不正确
UnknownAccountException
凭证(密码)不正确
IncorrectCredentialsException
凭证过期
ExpiredCredentialsException
使用 shiro 做异常处理的时候,尽量把异常信息表示的婉转一点,这 样有助于提升代码的安全性
Shiro–认证流程
A、通过 shiro 相关的 API 创建了 SecurityManager 以及获得
subject 实例
B、封装了 token 信息
C、详细描述
通过 subject.login(token)进行用户认证
Subject 接受 token 信息 ,通过 DelegatingSubject
将 token 委托给 securityManager 完成认证
securityManager 通过使用 DefaultSecurityManager
完成相关功能由 DefaultSecurityManager 中的 login 方法完
成对应的认证在 login 中调用了
AuthenticatingSecurityManager
中的 authenticate 方法完成认证
使用其中的doAuthenticate 获得realms信息如果是单个直接进
行比较,判断是否成功,如果是多个 raalm 需要使用验证策略完成
对应的认证工作
shiro 中的 JDBCRealm
注意:表名列名要相对应
shiro-jdbc.ini
[main]
dataSou=com.mchange.v2.c3p0.ComboPooledDataSource
dataSou.driverClass=com.mysql.jdbc.Driver
dataSou.jdbcUrl=jdbc:mysql://127.0.0.1:3306/shiro
dataSou.user=root
dataSou.password=root
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSou
securityManager.realm=$jdbcRealm
TestB .java
package com.bjsxt.shiro1;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class TestB {
public static void main(String[] args) {
//[1]解析shiro.ini文件
Factory<SecurityManager> factory =new IniSecurityManagerFactory("classpath:shiro-jdbc.ini");
//[2]通过SecurityManager工厂获得SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//[3]把SecurityManager对象设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//[4]通过SecurityUtils获得主体subject
Subject subject = SecurityUtils.getSubject();
//[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
//我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
UsernamePasswordToken token =new UsernamePasswordToken("root","123");
try {
//[6]进行身份的验证
subject.login(token);
//[7]通过方法判断是否登录成功
if(subject.isAuthenticated()){
System.out.println("登录成功");
}
} catch (IncorrectCredentialsException e) {
System.out.println("登录失败");
}catch (UnknownAccountException e){
System.out.println("用户名不正确");
}
}
}
认证策略
规定了如果有多个数据源
的时候应该如何操作
AtLeastOneSuccessfulStrategy
如果一个(或更多)Realm 验证成功,则整体的尝试被认为是成功的。 如果没有一个验证成功, 则整体尝试失败 类似于java 中的 &
FirstSuccessfulStrategy
只有第一个成功地验证的 Realm 返回的信息将被使用。所有进一步的 Realm 将被忽略。如果没有一个验证成功,则整体尝试失败。 类似于java 中的 &&
AllSucessfulStrategy
为了整体的尝试成功,所有配置的 Realm 必须验证成功。如果没有一个验 证成功,则整体尝试失败
shiro-jdbc.ini
[main]
#获得数据源A
dataSou=com.mchange.v2.c3p0.ComboPooledDataSource
dataSou.driverClass=com.mysql.jdbc.Driver
dataSou.jdbcUrl=jdbc:mysql://127.0.0.1:3306/shiro
dataSou.user=root
dataSou.password=root
#配置了jdbcRealmA
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSou
#获得数据源B
dataSou1=com.mchange.v2.c3p0.ComboPooledDataSource
dataSou1.driverClass=com.mysql.jdbc.Driver
dataSou1.jdbcUrl=jdbc:mysql://127.0.0.1:3306/shiro1
dataSou1.user=root
dataSou1.password=root
#配置了jdbcRealmB
jdbcRealm1=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm1.dataSource=$dataSou1
#配置验证器
authenticationStrategy=org.apache.shiro.authc.pam.AllSucessfulStrategy
#设置securityManager中realm
securityManager.realms=$jdbcRealm,$jdbcRealm1
securityManager.authenticator.authenticationStrategy=$authenticationStrategy
TestA.java
package com.bjsxt.shiro1;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class TestA {
public static void main(String[] args) {
/*Realm*/
//[1]解析shiro.ini文件
Factory<SecurityManager> factory =new IniSecurityManagerFactory("classpath:shiro-jdbc.ini");
//[2]通过SecurityManager工厂获得SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//[3]把SecurityManager对象设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//[4]通过SecurityUtils获得主体subject
Subject subject = SecurityUtils.getSubject();
//[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
//我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
UsernamePasswordToken token =new UsernamePasswordToken("sxt","123");
try {
//[6]进行身份的验证
subject.login(token);
//[7]通过方法判断是否登录成功
if(subject.isAuthenticated()){
System.out.println("登录成功");
}
} catch (IncorrectCredentialsException e) {
System.out.println("登录失败");
}catch (UnknownAccountException e){
System.out.println("用户名不正确");
}
}
}
自定义 Realm
[1] 为什么使用自定义 Realm
我们使用 JDBCRealm 的时候发现,shiro 的底层自己封装了数据库 表的名称和字段的名称,这样就造成了使用起来非常不方便
[2] 解决方案
自定义 Realm 我们如果自己定义 realm 的话,可以实现这个接口
[3] 步骤
新建表:admin
UserRealm.java
package com.bjsxt.shiro2;
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.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserRealm extends AuthorizingRealm {
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//System.out.println(authenticationToken.getPrincipal());
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro", "root", "root");
PreparedStatement prepareStatement = conn.prepareStatement("select pwd from admin where uname =? ");
prepareStatement.setObject(1,authenticationToken.getPrincipal());
ResultSet rs = prepareStatement.executeQuery();
while (rs.next()){
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),rs.getString("pwd"),"userRealm");
return info;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
shiro-jdbc2.ini
[main]
#设置securityManager中realm
userRealm=com.bjsxt.shiro2.UserRealm
securityManager.realms=$userRealm
TestB.java
package com.bjsxt.shiro2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class TestB {
public static void main(String[] args) {
/*Realm*/
//[1]解析shiro.ini文件
Factory<SecurityManager> factory =new IniSecurityManagerFactory("classpath:shiro-jdbc2.ini");
//[2]通过SecurityManager工厂获得SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//[3]把SecurityManager对象设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//[4]通过SecurityUtils获得主体subject
Subject subject = SecurityUtils.getSubject();
//[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
//我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
UsernamePasswordToken token =new UsernamePasswordToken("root","123");
try {
//[6]进行身份的验证
subject.login(token);
//[7]通过方法判断是否登录成功
if(subject.isAuthenticated()){
System.out.println("登录成功");
}
} catch (IncorrectCredentialsException e) {
System.out.println("登录失败");
}catch (UnknownAccountException e){
System.out.println("用户名不正确");
}
}
}
散列算法(算法加密)
A、 在身份认证的过程中往往都会涉及到加密,如果不加密,这个时 候信息就会非常的不安全,shiro 中提供的算法比较多 如 MD5 SHA 等
使用 MD5 进行 ‘’1111 加密 b59c67bf196a4758191e42f76670ceba
进行加盐操作
1111+姓名=
B、实现的案例
TestDemo .java
package com.bjsxt.shiro3;
import org.apache.shiro.crypto.hash.Md5Hash;
public class TestDemo {
public static void main(String[] args) {
//使用MD5加密
Md5Hash md5=new Md5Hash("1111");
System.out.println("1111=="+md5);
//加盐
md5=new Md5Hash("1111","sxt");
System.out.println("1111=="+md5);
//迭代次数
md5=new Md5Hash("123","sxt",2);
System.out.println("1111=="+md5);
}
}
shiro-jdbc3.ini
[main]
#设置securityManager中realm
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=md5
credentialsMatcher.hashIterations=2
userRealm=com.bjsxt.shiro3.UserRealm
userRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$userRealm
UserRealm .java
package com.bjsxt.shiro3;
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.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserRealm extends AuthorizingRealm {
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro", "root", "root");
PreparedStatement prepareStatement = conn.prepareStatement("select uname,pwd from admin ");
ResultSet rs = prepareStatement.executeQuery();
System.out.println(rs);
while (rs.next()){
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(rs.getString("uname"),rs.getString("pwd"), ByteSource.Util.bytes("sxt"),"userRealm");
return info;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
TestB.java
package com.bjsxt.shiro3;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class TestB {
public static void main(String[] args) {
/*Realm*/
//[1]解析shiro.ini文件
Factory<SecurityManager> factory =new IniSecurityManagerFactory("classpath:shiro-jdbc3.ini");
//[2]通过SecurityManager工厂获得SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//[3]把SecurityManager对象设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//[4]通过SecurityUtils获得主体subject
Subject subject = SecurityUtils.getSubject();
//[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
//我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
UsernamePasswordToken token =new UsernamePasswordToken("root","111");
try {
//[6]进行身份的验证
subject.login(token);
//[7]通过方法判断是否登录成功
if(subject.isAuthenticated()){
System.out.println("登录成功");
}
} catch (IncorrectCredentialsException e) {
System.out.println("登录失败");
}catch (UnknownAccountException e){
System.out.println("用户名不正确");
}
}
}
授权
授权:给身份认证通过的任授予某些资源的访问权限
权限的粒度 粗粒度 细粒度
粗粒度
User 具有 CRUD 的操作 通常指的是表的操作
细粒度
只允许查询 id=1 的用户 使用业务代码实现
Shiro 的授权是粗粒度
角色:角色就是权限的集合
Shiro 中代码的实现
shiro.ini
#指定具体的用户
[users]
zs=123,role1,role2
sxt=root
#角色的定义
[roles]
role1=add,update,delete
role2=find
#给对象中的属性赋值
#[main]
TestA.java
package com.bjsxt.shiro1;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import java.util.Arrays;
public class TestA {
public static void main(String[] args) {
//[1]解析shiro.ini文件
Factory<SecurityManager> factory =new IniSecurityManagerFactory("classpath:shiro.ini");
//[2]通过SecurityManager工厂获得SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//[3]把SecurityManager对象设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//[4]通过SecurityUtils获得主体subject
Subject subject = SecurityUtils.getSubject();
//[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
//我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
UsernamePasswordToken token =new UsernamePasswordToken("zs","123");
try {
//[6]进行身份的验证
subject.login(token);
} catch (IncorrectCredentialsException e) {
System.out.println("登录失败");
}
//授权的查询
//基于角色的授权
boolean flag = subject.hasRole("role1");
//System.out.println(flag);
//判断是否具有多个角色
boolean[] booleans = subject.hasRoles(Arrays.asList("role1", "role3"));
/*for(Boolean b:booleans){
System.out.println(b);
}*/
//可以使用checkRole判断指定用户是否具有对应角色
//如果指定用户下没有对应的角色就会抛出异常UnauthorizedException
/* subject.checkRole("role3");
subject.checkRoles("role1","role2");*/
//基于资源的授权
boolean flag2 = subject.isPermitted("iii");
//System.out.println(flag2);
//判读是否具有多个资源
boolean permittedAll = subject.isPermittedAll("add", "oo", "ii");
//通过checkPermission 进行判断指定用户下是否有指定的资源
//如果没有就会抛出UnauthorizedException
subject.checkPermission("uu");
subject.checkPermissions("ii","ooo","add");
}
}
Shiro 中的授权检查的 3 种方式
A、 编程式
TestA.java
B、 注解式
package com.bjsxt.shiro1;
import org.apache.shiro.authz.annotation.RequiresRoles;
public class Role {
@RequiresRoles("管理员")
public void aa(){
}
}
C、 标签配置
<shiro:hasPermission name="add">
<a>添加操作</a>
</shiro:hasPermission>
自定义 Realm 实现授权
我们仅仅通过配置文件指定授权是非常的不灵活的,在实际的应用中 我们是将用户的信息和合权限信息保存到数据库中,我们是从数据库 中获得用户的信息 ,使用 JDBCRealm 进行授权 。使用 JDBCRealm 操 作的时候也不是很灵活。所以我们一般使用自定义 Realm 实现授权。
shiro-jdbc.ini
[main]
#设置securityManager中realm
userRealm=com.bjsxt.shiro.UserRealm
securityManager.realms=$userRealm
UserRealm.java
package com.bjsxt.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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class UserRealm extends AuthorizingRealm {
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//System.out.println(authenticationToken.getPrincipal());
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro", "root", "root");
PreparedStatement prepareStatement = conn.prepareStatement("select pwd from admin where uname =? ");
prepareStatement.setObject(1,authenticationToken.getPrincipal());
ResultSet rs = prepareStatement.executeQuery();
while (rs.next()){
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),rs.getString("pwd"),"userRealm");
return info;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username = principalCollection.getPrimaryPrincipal().toString();
//获得username 然后去数据库查询这个用户对应的角色,在根据角色查询出指定角色下对应的菜单,
//返回给指定角色下的所有菜单--List集合
System.out.println("username="+username);
//模拟数据库查的菜单
List<String> list =new ArrayList<>();
list.add("updateUser");
list.add("addUser");
list.add("deleteUser");
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
for(String l:list){
simpleAuthorizationInfo.addStringPermission(l);
}
return simpleAuthorizationInfo;
}
}
TestB.java
package com.bjsxt.shiro;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class TestB {
public static void main(String[] args) {
/*Realm*/
//[1]解析shiro.ini文件
Factory<SecurityManager> factory =new IniSecurityManagerFactory("classpath:shiro-jdbc2.ini");
//[2]通过SecurityManager工厂获得SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//[3]把SecurityManager对象设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//[4]通过SecurityUtils获得主体subject
Subject subject = SecurityUtils.getSubject();
//[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
//我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
UsernamePasswordToken token =new UsernamePasswordToken("root","123");
try {
//[6]进行身份的验证
subject.login(token);
//[7]通过方法判断是否登录成功
if(subject.isAuthenticated()){
System.out.println("登录成功");
//授权的校验
System.out.println("是否存在该菜单:"+subject.isPermitted("updateUser2123"));
}
} catch (IncorrectCredentialsException e) {
System.out.println("登录失败");
}catch (UnknownAccountException e){
System.out.println("用户名不正确");
}
}
}
SSM 整合 Shiro
【A】 导包
【B】 书写 web.xm
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--解析Springmvc.xml-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--初始化参数 contextConfigLocation-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- / 除了jsp以外的所有资源都可以访问指定的servlet-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--解析applicationContext-*.xml文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--注册了DelegatingFilterProxy 使用代理把servlet容器中fiter和Spring 中的bean进行连接-->
<filter>
<filter-name>shiro</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!--设置为truez之后可以使用过滤器中初始化 销毁等方法-->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!--给注册了的bend起名称-->
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shiroFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiro</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
【C】书写了applicationContext-shiro.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--[A]注册凭证匹配器-->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5"></property>
<property name="hashIterations" value="2"></property>
</bean>
<!--[B]注册自定义Realm-->
<bean id="userRealm" class="com.bjsxt.realm.UserRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
<!--[C]注册securityManager-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realms" ref="userRealm"></property>
</bean>
<!--[D]注册ShiroFilterFactoryBean对象-->
<!-- bean对象中的id名称必须和web.xml中targetBeanName保持一致-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
<property name="loginUrl" value="/login"></property>
<property name="successUrl" value="/success.jsp"></property>
<property name="unauthorizedUrl" value="/error.jsp"></property>
<!--设置过滤器链的属性 authc拦截指定路径 anon放行资源 -->
<property name="filterChainDefinitions">
<value>
/login=authc
<!--配置退出的过滤器 如果没有配置退出的页面,默认是退到项目的默认网页中 index.jsp /index.html-->
/loginOut=logout
/**=anon
</value>
</property>
</bean>
<!--配置退出的过滤器-->
<bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value="login.jsp"></property>
</bean>
<!--表单过滤器-->
<bean id="authc" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
<property name="usernameParam" value="uname"></property>
<property name="passwordParam" value="pwd"></property>
<property name="rememberMeParam" value="rm"></property>
</bean>
</beans>
【D】创建实体
package com.bjsxt.pojo;
import java.io.Serializable;
public class Admin implements Serializable {
private String username;
private String password;
private String salt;
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public Admin(String username, String password) {
this.username = username;
this.password = password;
}
public Admin(){}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Admin{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
【E】自定义 realm
package com.bjsxt.realm;
import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
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.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserRealm extends AuthorizingRealm {
@Autowired
AdminService adminService;
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
Admin admin = adminService.findPwd(authenticationToken.getPrincipal().toString());
if(admin!=null){
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),admin.getPassword(), ByteSource.Util.bytes(admin.getSalt()),"userRealm");
return info;
}
return null;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
【F】书写业务层
package com.bjsxt.service;
import com.bjsxt.pojo.Admin;
public interface AdminService {
//用户的登陆
public Admin login(String uname, String pwd);
//获得用户密码 延迟操作
public Admin findPwd(String username);
}
package com.bjsxt.service.impl;
import com.bjsxt.mapper.AdminMapper;
import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("admins")
public class AdminServiceImpl implements AdminService {
@Autowired
AdminMapper adminMapper;
@Override
public Admin login(String uname, String pwd) {
return adminMapper.selectOne(uname, pwd);
}
@Override
public Admin findPwd(String username) {
return adminMapper.selectPwd(username);
}
}
【G】书写控制层
package com.bjsxt.controller;
import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.lang.model.element.UnknownAnnotationValueException;
import javax.servlet.http.HttpServletRequest;
@Controller
public class AdminController {
@RequestMapping("login")
public String login(HttpServletRequest req){
//查看具体的异常信息,获得一场的信息名称
Object ex = req.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
if(UnknownAccountException.class.getName().equals(ex)){
req.setAttribute("msg","用户名错误");
}else if(IncorrectCredentialsException.class.getName().equals(ex)){
req.setAttribute("msg","凭证不正确");
}else{
req.setAttribute("msg","未知异常");
}
return "/error.jsp";
}
}
页面:
error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
$END$
</body>
</html>
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登陆</title>
<base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
<h3>用户登陆</h3>
<form action="login" method="post">
<p>
用户名:<input type="text" name="username"/>${msg}
</p>
<p>
密码:<input type="text" name="password"/>
</p>
<p>
<input type="submit" value="提交"/>
</p>
</form>
</body>
</html>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成功页面</title>
<base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
<h3>成功页面</h3>
<h4 style="float: right"><a href="loginOut">退出</a></h4>
<h3>sessionID:<%=session.getid()%></h3>
</body>
</html>
shiro实现授权
准备:
/**zs登录成功看到的菜单**/
SELECT mmid FROM 'role_menu' WHERE rid=2
SELECT * FROM menu WHERE mmin IN(SELECT mmid FROM 'role_menu' WHERE rid=2) AND pid=2
实现步骤
添加实体
Admin
package com.bjsxt.pojo;
import java.io.Serializable;
import java.util.List;
public class Admin implements Serializable {
private String username;
private String password;
private String salt;
private int rid;
//保存菜单的集合
private List<Menu> list;
//保存权限的集合
private Role role;
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public List<Menu> getList() {
return list;
}
public void setList(List<Menu> list) {
this.list = list;
}
public int getRid() {
return rid;
}
public void setRid(int rid) {
this.rid = rid;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public Admin(String username, String password) {
this.username = username;
this.password = password;
}
public Admin(){}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Admin{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
Menu
package com.bjsxt.pojo;
import java.io.Serializable;
import java.util.List;
public class Menu implements Serializable {
private Integer mmid;
private String mname;
private String url;
private int pid;
private List<Menu> list;
public List<Menu> getList() {
return list;
}
public void setList(List<Menu> list) {
this.list = list;
}
public Menu(Integer mmid, String mname, String url, int pid) {
this.mmid = mmid;
this.mname = mname;
this.url = url;
this.pid = pid;
}
public Menu(){}
public Integer getMmid() {
return mmid;
}
public void setMmid(Integer mmid) {
this.mmid = mmid;
}
public String getMname() {
return mname;
}
public void setMname(String mname) {
this.mname = mname;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
@Override
public String toString() {
return "Menu{" +
"mmid=" + mmid +
", mname='" + mname + '\'' +
", url='" + url + '\'' +
", pid=" + pid +
'}';
}
}
Role
package com.bjsxt.pojo;
import java.io.Serializable;
public class Role implements Serializable {
private int rid;
private String rname;
public Role(int rid, String rname) {
this.rid = rid;
this.rname = rname;
}
public Role(){}
public int getRid() {
return rid;
}
public void setRid(int rid) {
this.rid = rid;
}
public String getRname() {
return rname;
}
public void setRname(String rname) {
this.rname = rname;
}
@Override
public String toString() {
return "Role{" +
"rid=" + rid +
", rname='" + rname + '\'' +
'}';
}
}
添加Mapper
Menu
package com.bjsxt.mapper;
import com.bjsxt.pojo.Menu;
import java.util.List;
public interface MenuMapper {
//菜单的查询
public List<Menu> selectMore(int rid,int pid);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.MenuMapper">
<select id="selectMore" resultType="menu">
SELECT * FROM menu WHERE mmid IN (SELECT mmid FROM role_menu WHERE rid =#{0} ) AND pid =#{1}
</select>
</mapper>
Admin
package com.bjsxt.mapper;
import com.bjsxt.pojo.Admin;
public interface AdminMapper {
//查询单个操作
public Admin selectOne(String uname, String pwd);
public Admin selectPwd(String username);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.AdminMapper">
<select id="selectOne" resultType="admin">
SELECT * from admin where username =#{param1} and password =#{param2}
</select>
<select id="selectPwd" resultType="admin">
SELECT * from admin where username =#{param1}
</select>
</mapper>
Role
package com.bjsxt.mapper;
import com.bjsxt.pojo.Role;
public interface RoleMapper {
//查询角色的名称
public Role selectOne(int rid);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.RoleMapper">
<select id="selectOne" resultType="role">
SELECT * from role where rid =#{0}
</select>
</mapper>
添加service
Menu
package com.bjsxt.service;
import com.bjsxt.pojo.Menu;
import java.util.List;
public interface MenuService {
//查询指定角色的菜单
public List<Menu> findMoreMenus(int rid);
}
package com.bjsxt.service.impl;
import com.bjsxt.mapper.MenuMapper;
import com.bjsxt.pojo.Menu;
import com.bjsxt.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MenuServiceImpl implements MenuService {
@Autowired
MenuMapper menuMapper;
@Override
public List<Menu> findMoreMenus(int rid) {
//指定角色下的一级菜单
List<Menu> list = menuMapper.selectMore(rid, 0);
for(Menu menu:list){
//一级菜单的mmid
Integer mmid = menu.getMmid();
//指定一级菜单下对应的二级菜单
List<Menu> list2 = menuMapper.selectMore(rid, mmid);
//把二级菜单保存到指定的一级菜单对象中
menu.setList(list2);
}
return list;
}
}
Admin
package com.bjsxt.service.impl;
import com.bjsxt.mapper.AdminMapper;
import com.bjsxt.mapper.RoleMapper;
import com.bjsxt.pojo.Admin;
import com.bjsxt.pojo.Menu;
import com.bjsxt.service.AdminService;
import com.bjsxt.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("admins")
public class AdminServiceImpl implements AdminService {
@Autowired
AdminMapper adminMapper;
@Autowired
MenuService menuService;
@Autowired
RoleMapper roleMapper;
@Override
public Admin login(String uname, String pwd) {
return adminMapper.selectOne(uname, pwd);
}
@Override
public Admin findPwd(String username) {
Admin admin = adminMapper.selectPwd(username);
List<Menu> list = menuService.findMoreMenus(admin.getRid());
//把菜单保存到执行的admin对象中
admin.setList(list);
//把用户的身份保存admin中
admin.setRole(roleMapper.selectOne(admin.getRid()));
return admin;
}
}
package com.bjsxt.service;
import com.bjsxt.pojo.Admin;
public interface AdminService {
//用户的登陆
public Admin login(String uname, String pwd);
//获得用户密码 颜值操作
public Admin findPwd(String username);
}
添加realm【授权】
package com.bjsxt.realm;
import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserRealm extends AuthorizingRealm {
@Autowired
AdminService adminService;
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
Admin admin = adminService.findPwd(authenticationToken.getPrincipal().toString());
if(admin!=null){
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(admin,admin.getPassword(), ByteSource.Util.bytes(admin.getSalt()),"userRealm");
return info;
}
return null;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Admin admin = (Admin) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//把角色的名称保持到SimpleAuthorizationInfo
info.addRole(admin.getRole().getRname());
return info;
}
}
添加controller
package com.bjsxt.controller;
import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.lang.model.element.UnknownAnnotationValueException;
import javax.servlet.http.HttpServletRequest;
@Controller
public class AdminController {
@RequestMapping("findMoreMenus")
public String findMoreMenus(HttpServletRequest req){
//获得验证成功以后的admin 对象
Admin admin = (Admin) SecurityUtils.getSubject().getPrincipal();
req.setAttribute("list",admin.getList());
return "/success.jsp";
}
@RequestMapping("login")
public String login(HttpServletRequest req){
//查看具体的异常信息,获得一场的信息名称
Object ex = req.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
if(UnknownAccountException.class.getName().equals(ex)){
req.setAttribute("msg","用户名错误");
}else if(IncorrectCredentialsException.class.getName().equals(ex)){
req.setAttribute("msg","凭证不正确");
}else{
req.setAttribute("msg","未知异常");
}
return "/error.jsp";
}
}
页面
error
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
index
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
$END$
</body>
</html>
login
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登陆</title>
<base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
<h3>用户登陆</h3>
<form action="login" method="post">
<p>
用户名:<input type="text" name="uname"/>${msg}
</p>
<p>
密码:<input type="text" name="pwd"/>
</p>
<p>
<input type="submit" value="提交"/>
</p>
</form>
</body>
</html>
success
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
<title>成功页面</title>
<base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
<h3>成功页面</h3>
<h4 style="float: right"><a href="loginOut">退出</a> </h4>
<h3>sessionID:<%=session.getId()%></h3>
<hr/>
<shiro:hasRole name="学生">
<h1>查询</h1>
</shiro:hasRole>
<shiro:hasRole name="老师">
<h1>删除</h1>
</shiro:hasRole>
<shiro:hasRole name="管理员">
<h1>查询</h1>
<h1>删除</h1>
<h1>添加</h1>
</shiro:hasRole>
<hr/>
<c:forEach items="${list}" var="menu">
<h4>${menu.mname}</h4>
<c:forEach items="${menu.list}" var="menu2">
<a href="${menu2.url}">${menu2.mname}</a><br/>
</c:forEach>
</c:forEach>
</body>
</html>
SessionManager 的管理
设置管理登录5秒后失效
实现步骤
<!--[C]注册securityManager-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realms" ref="userRealm"></property>
<property name="sessionManager" ref="sessionManager"></property>
</bean>
<!--配置会话管理器-->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!–单位是毫秒–>
<property name="globalSessionTimeout" value="5000"></property>
<!–删除无效的session –>
<property name="deleteInvalidSessions" value="true"></property>
</bean>
RememberMe 记住我
A、 所有的实体类 都必须实现序列化接口
同上
B、 更改 JSP 页面
login
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登陆</title>
<base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
<h3>用户登陆</h3>
<form action="login" method="post">
<p>
用户名:<input type="text" name="uname"/>${msg}
</p>
<p>
密码:<input type="text" name="pwd"/>
</p>
<p>
记住我:<input type="checkbox" checked name="rm"/>
</p>
<p>
<input type="submit" value="提交"/>
</p>
</form>
</body>
</html>
C、 配置 bend 对象
<!--设置过滤器链的属性 authc拦截指定路径 anon放行资源 -->
<property name="filterChainDefinitions">
<value>
/login=authc
<!--配置退出的过滤器 如果没有配置退出的页面,默认是退到项目的默认网页中 index.jsp /index.html-->
/loginOut=logout
<!--记住我的 路径-->
/findMoreMenus=user
/**=anon
</value>
</property>
<!--注册SimpleCookie-->
<bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!--设置cookie 的名称-->
<property name="name" value="rm"></property>
<!--设置cookie的有效时间 单位秒 7天免登陆-->
<property name="maxAge" value="604800"></property>
</bean>
<!--注册rememberMeManger-->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="simpleCookie"></property>
</bean>
D、测试