Shiro框架作为Java安全框架,目前是非常火的,目前市面上比较火的Java安全框架就属于Shiro
和SpringSecurity
。虽然它的功能没有Spring Security那么强大,但是Shiro的API简单,易于使用。而且相比使用原生的RBAC模型实现认证和授权功能,使用Shiro可以构建更强大的认证授权系统。然后打算写几篇博客记录以及分享Shiro体系知识,达到从认识Shiro到实战的境界。
正在登录的用户
)是否是应用的合法用户。一般提供身份证,用户名/密码来证明。principals
(身份)和credentials
(凭证)给shiro,以此来认证用户身份。principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。credentials:凭证,即只有主体知道的安全值,如密码/数字证书等。最常见的principals
和credentials
组合就是用户名/密码了。接下来先进行一个基本的身份认证。
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.1.3version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
<version>1.2.2version>
dependency>
[users]
zwq=22
zhangsan=18
public class LoginLogout {
public static void main(String[] args) {
//1.根据.ini配置文件获取SecurityManagerFactory
IniSecurityManagerFactory factory =
new IniSecurityManagerFactory("classpath:shiro.ini");
//2.使用工厂获取SecurityManager示例
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3.获取主体
Subject subject = SecurityUtils.getSubject();
//4.封装token
UsernamePasswordToken token = new UsernamePasswordToken("zwq", "22");
//5.执行认证逻辑:登录
subject.login(token);
//6.判断是否认证成功
System.out.println("用户是否认证:"+subject.isAuthenticated());
//7.退出
subject.logout();
//8.再次判断是否认证成功
System.out.println("用户是否认证:"+subject.isAuthenticated());
}
}
subject.login()
),底层是委托SecurityManager进行认证(SecurityManager.login()
),认证是否成功可以调用主体的isAuthenticated()
方法判断,主体进行退出操作时(subject.logout()
),底层也是委托SecurityManager执行退出操作(SecurityManager.logout()
)。一是用户名正确而密码错误
,这种情况会出现IncorrectCredentialsException
异常,所以以后出现这个异常就知道是密码错了。//用户名正确而命名错误
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "22");
org.apache.shiro.authc.IncorrectCredentialsException:
Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - zhangsan, rememberMe=false] did not match the expected credentials.
二是用户名错误而密码正确
,这种情况会出现UnknownAccountException
异常,所以以后出现这个异常就知道是用户名错了。//用户名错误而密码正确
UsernamePasswordToken token = new UsernamePasswordToken("zs", "18");
org.apache.shiro.authc.UnknownAccountException:
Realm [org.apache.shiro.realm.text.IniRealm@7006c658] was unable to find account data for the submitted AuthenticationToken
[org.apache.shiro.authc.UsernamePasswordToken - zs, rememberMe=false].
上面我们学会了使用Shiro编写认证代码,接下来打个断点查看并分析认证源码:
授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。
不管是使用Shiro框架,还是其他安全框架,都会涉及这几个关键对象:主体、角色、资源、权限。
Shiro支持三种方式的授权
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
@RequiresRoles("admin")
public void deleteUser() {
//有admin权限才执行
}
<shiro:hasRole name="admin">
<!— 有权限才解析这段HTML代码 —>
shiro:hasRole>
授权只能在认证成功之后才执行,就像上面说的,如果认证不通过就会报异常,就不可能再执行授权代码了。而且在我们经常做的Web项目中,用户输入用户名和密码进行登录(这就是认证过程),只有成功登录之后才能进入系统,登录不成功还是会返回登录页面。
接下来在JavaSE环境下使用Shiro编写代码判断用户是否拥有某些角色。
用户名=密码,角色1,角色2,...
[users]
zwq=22,admin,tester
zhangsan=18,tester
public class LoginLogout {
private static Subject subject;
public static void main(String[] args) {
//认证
login("classpath:users-roles.ini","zhangsan","18");
//判断用户是否拥有一组权限。是,返回true;不是,返回false。
System.out.println(subject.hasAllRoles(Arrays.asList("admin", "tester")));
//判断用户是否拥有某个权限
System.out.println(subject.hasRole("tester"));
//
boolean[] hasRoles = subject.hasRoles(Arrays.asList("admin", "tester", "boss"));
for (int i = 0; i < hasRoles.length; i++) {
System.out.println(hasRoles[i]);
}
}
/**
封装认证逻辑代码
*/
public static void login(String configFile,String username,String password){
//1.根据.ini配置文件获取SecurityManagerFactory
IniSecurityManagerFactory factory =
new IniSecurityManagerFactory(configFile);
//2.使用工厂获取SecurityManager示例
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3.获取主体
subject = SecurityUtils.getSubject();
//4.封装token
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//5.执行认证逻辑:登录
subject.login(token);
}
}
public class LoginLogout {
private static Subject subject;
public static void main(String[] args) {
//认证
login("classpath:users-roles.ini","zhangsan","18");
subject.checkRole("admin");
subject.checkRoles(Arrays.asList("admin", "tester"));
subject.checkRoles(Arrays.asList("admin", "tester", "boss"));
}
/**
封装认证逻辑代码
*/
public static void login(String configFile,String username,String password){
//1.根据.ini配置文件获取SecurityManagerFactory
IniSecurityManagerFactory factory =
new IniSecurityManagerFactory(configFile);
//2.使用工厂获取SecurityManager示例
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3.获取主体
subject = SecurityUtils.getSubject();
//4.封装token
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//5.执行认证逻辑:登录
subject.login(token);
}
}
[users]
zwq=22,admin,tester
zhangsan=18,tester
[roles]
admin=user:insert,user:select,user:update
tester=user:select,user:delete
public class LoginLogout {
private static Subject subject;
public static void main(String[] args) {
login("classpath:users-roles-permissions.ini","zhangsan","18");
//判断拥有某个权限
System.out.println(subject.isPermitted("user:delete"));
//判断拥有一组权限
System.out.println(subject.isPermittedAll("user:insert", "user:create"));
boolean[] permitted = subject.isPermitted("user:insert", "user:create");
for (int i = 0; i < permitted.length; i++) {
System.out.println(permitted[i]);
}
}
public static void login(String configFile,String username,String password){
//1.根据.ini配置文件获取SecurityManagerFactory
IniSecurityManagerFactory factory =
new IniSecurityManagerFactory(configFile);
//2.使用工厂获取SecurityManager示例
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3.获取主体
subject = SecurityUtils.getSubject();
//4.封装token
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//5.执行认证逻辑:登录
subject.login(token);
}
}
public class LoginLogout {
private static Subject subject;
public static void main(String[] args) {
login("classpath:users-roles-permissions.ini","zhangsan","18");
//判断拥有某个权限
subject.checkPermission("user:insert");
//判断拥有一组权限
subject.checkPermissions("user:insert", "user:create");
}
public static void login(String configFile,String username,String password){
//1.根据.ini配置文件获取SecurityManagerFactory
IniSecurityManagerFactory factory =
new IniSecurityManagerFactory(configFile);
//2.使用工厂获取SecurityManager示例
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3.获取主体
subject = SecurityUtils.getSubject();
//4.封装token
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//5.执行认证逻辑:登录
subject.login(token);
}
}