Shiro官网:http://shiro.apache.org/
以下来自官网简介:
Apache Shiro是一个功能强大、易于使用的Java安全框架,它执行身份验证、授权、加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的Web和企业应用程序。
从应用程序的角度观察 Shiro 的工作流程:
Shiro 架构:
创建 Maven 工程,导入依赖 jar 包
org.apache.shiro
shiro-core
1.3.2
org.slf4j
slf4j-nop
1.7.2
org.slf4j
slf4j-api
1.7.21
junit
junit
4.12
test
配置 shiro.ini 文件如下
[users]
##用户名=密码,角色
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz
[roles]
##角色=权限(*代表全部权限,一个角色可以有多个权限,一个用户可以有多个角色,都是多对多关系)
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5
测试类
package com.jiker.shirose;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
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.session.Session;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ShiroTest {
private static final transient Logger log = LoggerFactory.getLogger(ShiroTest.class);
@Test
public void test(){
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute("someKey","aValue");
String value = (String) session.getAttribute("someKey");
if (value.equals("aValue")){
log.info("Retrieved the corrent value! {" + value + "}");
}
if (!currentUser.isAuthenticated()){
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr","vespa");
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (UnknownAccountException uae) {
log.info("用户名不存在:" + token.getPrincipal ());
} catch (IncorrectCredentialsException ice) {
log.info ("账户密码 " + token.getPrincipal () + " 不正确!");
} catch (LockedAccountException lae) {
log.info("用户名 " + token.getPrincipal () + " 被锁定 !");
} catch (AuthenticationException ae){
}
}
log.info("-------> User {" + currentUser.getPrincipal() + "} logged in successfully.");
if (currentUser.hasRole("schwartz")){
log.info("------> May the Schwartz be with you!");
} else {
log.info("------>Hello mere mortal.");
return;
}
if (currentUser.isPermitted("lightsaber:weild")){
log.info("You may use a lightsaber ring. Use it wisely");
} else {
log.info("Sorry,lightsaber rings are for schwartz masters only.");
}
if (currentUser.isPermitted("winnebago:drive:eagle5")){
log.info("You are permitted to 'driver' the winnebago with license plate (id) 'eagle5'.");
} else {
log.info("Sorry,you aren't allowed to drive the 'eagle5' winnebago!");
}
currentUser.logout();
System.exit(0);
}
}
流程解析:
1、使用工厂的方式,读取类路径下的 .ini
文件,进而返回一个 SecurityManager
的实例
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
2、让 SecurityManager
实例在 JVM
虚拟机中变为单例且可以访问的
注:大部分应用都不再使用此方式
SecurityUtils.setSecurityManager(securityManager);
3、获取当前的 Subject
,调用 SecurityUtils.getSubject()
Subject currentUser = SecurityUtils.getSubject();
4、测试使用 Session
获取 Session
:调用 Subject#getSession()
Session session = currentUser.getSession();
session.setAttribute("someKey","aValue");
String value = (String) session.getAttribute("someKey");
if (value.equals("aValue")){
log.info("Retrieved the corrent value! {" + value + "}");
}
5、测试当前的用户是否已经被认证,即是否已经登录
调用 Subject
的 isAuthenticated()
由于当前还未认证,则将用户名、密码封装为 UsernamePasswordToken
对象
if (!currentUser.isAuthenticated()){
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr","vespa");
token.setRememberMe(true);
6、执行登录
能否登录成功取决于配置文件中是否配置了对应的用户名:lonestarr
、密码:vespa
同时可能抛出登录时的异常
try {
currentUser.login(token);
}
配置文件 shiro.ini 中存在
lonestarr = vespa, goodguy, schwartz
//若没有指定的用户,则抛出 UnknownAccountException 异常
catch (UnknownAccountException uae) {
log.info("用户名不存在:" + token.getPrincipal ());
}
//若账户存在但密码不匹配,则抛出 IncorrectCredentialsException 异常
catch (IncorrectCredentialsException ice) {
log.info ("账户密码 " + token.getPrincipal () + " 不正确!");
}
//用户被锁定的异常: LockedAccountException
catch (LockedAccountException lae) {
log.info("用户名 " + token.getPrincipal () + " 被锁定 !");
}
//所有认证时异常的父类
catch (AuthenticationException ae){
}
7、登录验证后,测试是否有某一个角色
if (currentUser.hasRole("schwartz")){
log.info("------> May the Schwartz be with you!");
} else {
log.info("------>Hello mere mortal.");
return;
}
配置文件中 lonestarr 用户含有 schwartz 角色
lonestarr = vespa, goodguy, schwartz
8、测试用户是否有某一个行为,调用 Subject
的 isPermitted()
方法
if (currentUser.isPermitted("lightsaber:weild")){
log.info("You may use a lightsaber ring. Use it wisely");
} else {
log.info("Sorry,lightsaber rings are for schwartz masters only.");
}
9、测试用户是否具备某一更具体的行为
if (currentUser.isPermitted("winnebago:drive:eagle5")){
配置文件中
goodguy = winnebago:drive:eagle5
意为:允许对 winnebago 类型的 eagle5 做 drive 动作
10、执行登出,调用 Subject
的 logout()
方法
currentUser.logout();
时间:2019.6.29 12:05