目录
前提
学习本课程内容,请确保你已经具有如下内容的使用经验:
- maven
- idea
- spring、springboot等
1.使用maven创建一个shiro1项目
2.导入shiro核心jar包
本教程使用maven导入
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
1.7.1为文章编写时的最新版本,大家可以选择适合自己的版本
slf4j依赖是shiro的依赖,不依赖也不会报错,建议依赖
shiro.ini文件
在src/main/resources目录下创建一个
shiro.ini文件内容如下:
[users]
admin = password,admin
user1 = password, role1, role2
user2 = password, role1
user3 = password
[roles]
# 'admin' 角色包含所有权限, 权限的值设定为 '*'
admin = *
# 角色1包含"p1:"开头的所有权限
role1 = p1:*
# 角色2拥有两个权限p1:o1:c1,p2:o2:c2
role2 = p1:o1:c1,p2:o2:c2
[users]格式说明
username
= password
,roleName1,roleName2,...,roleNameN
- 等号左侧的值是用户名
- 等号右边的第一个值是用户的密码。必须输入密码。
- 密码后的任何逗号分隔值都是分配给该用户的角色的名称。角色名称是可选的。
- 密码还可以加密,这个我们后面再讨论。(可通过myRealm.setCredentialsMatcher(sha256Matcher))CredentialsMatcher就是我们的密码加密策略。
[roles]格式说明
rolename
=权限定义1,权限定义2,...,权限定义N
其中每个权限定义是一个任意字符串,但大多数人将要使用符号串,当然这些权限不要重名了。shiro还支持带*号的复杂格式的权限(更详细的权限规则请参考官网http://shiro.apache.org/permissions.html)
[main]说明
本例暂时没有使用,其主要用于定义SecurityManager
实例及其任何依赖项,例如Realm。
[main]
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
myRealm = com.company.security.shiro.DatabaseRealm
myRealm.connectionTimeout = 30000
myRealm.username = jsmith
myRealm.password = secret
myRealm.credentialsMatcher = $sha256Matcher
securityManager.sessionManager.globalSessionTimeout = 1800000
使用[main]需要使用如下代码启用shiro
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
IniSecurityManagerFactory会自动装配[main]中定义的各种属性类似于spring的依赖注入,由于我们实际开发中shiro常常是和spring一起使用的,所以ini方式是比较少用的。在1.7.1版本中IniSecurityManagerFactory已经被@Deprecated不建议使用了。
3.编写示例代码
package com.yyoo.mytest.shiro1.demo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
public class Demo1 {
public static void main(String[] args) {
//1.定义领域
Realm realm = new IniRealm("classpath:shiro.ini");
//2.定义shiro的核心SecurityManager,注意import,java.lang包也有个SecurityManager,但不是我们需要的
SecurityManager securityManager = new DefaultSecurityManager(realm);
//3.为全局对象SecurityUtils设置securityManager
SecurityUtils.setSecurityManager(securityManager);
// 以上为shiro的初始化(启用)代码
// 以下为shiro的登录认证等代码
Subject subject = SecurityUtils.getSubject();
System.out.println("登录前:");
print(subject);
// 此处更换其他用户名密码试试
UsernamePasswordToken token = new UsernamePasswordToken("admin","password");
subject.login(token);
System.out.println("\n\n登录后:");
print(subject);
// 退出
subject.logout();
System.out.println("\n\n退出后:");
print(subject);
}
public static void print(Subject subject){
System.out.println("是否认证:" + subject.isAuthenticated());
System.out.println("是否是记住登录的:" + subject.isRemembered());
System.out.println("是否是角色role1:" + subject.hasRole("role1"));
System.out.println("是否具有权限p1:" + subject.isPermitted("p1"));
System.out.println("是否具有权限p1:o1:c1:" + subject.isPermitted("p1:o1:c1"));
System.out.println("是否具有权限p2:o2:c2:" + subject.isPermitted("p2:o2:c2"));
}
}
大家自行把用户admin、user1、user2、user3和其他没有定义的用户带入方法执行看看结果,认真分析结果,对你理解shiro的权限控制会有帮助。
4.登录异常的处理
当我们带入其他没有定义的用户执行时,会出现如下异常:
Exception in thread "main" org.apache.shiro.authc.UnknownAccountException: Realm [org.apache.shiro.realm.text.IniRealm@66cd51c3] was unable to find account data for the submitted AuthenticationToken [org.apache.shiro.authc.UsernamePasswordToken - user33, rememberMe=false].
at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:184)
at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:273)
at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198)
at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106)
at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:275)
at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260)
UnknownAccountException通过异常名就能知道,这是用户名不存在的异常,但我们在实际使用中最好不要提示“用户名不存在”,避免被人暴力破解账号。我们示例中也没有对这些异常进行处理规避,所以我们的示例代码还得优化,将
subject.login(token);
这行代码优化如下:
try {
subject.login(token);
} catch (UnknownAccountException e) {// 用户不存在
logger.error("用户名或密码错误",e);
throw new RuntimeException("用户名密码错误");
} catch (LockedAccountException e) {
logger.error("账户被锁定",e);
throw new RuntimeException("账户被锁定");
} catch (IncorrectCredentialsException e) {// 密码错误
logger.error("用户名或密码错误",e);
throw new RuntimeException("用户名密码错误");
}catch (AuthenticationException e){
logger.error("用户名密码错误",e);
throw new RuntimeException("用户名密码错误");
}
总结
我们的HelloWorld虽然并不复杂,也不够全面,但shiro的基本功能都得以体现,特别用户、角色、权限以及权限的简单规则我们都有了初步的认识,能清楚认识到这几个点,对我们后续架构中设计项目的权限功能会有很大帮助。
上一篇:001-shiro简介
下一篇:003-认证