Shiro学习笔记

介绍

Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能,对于任何一个应用程序,Shiro 都可以提供全面的安全管理服务。并且相对于其他安全框架,Shiro 要简单的多。

入门示例代码

引入pom文件的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>

单元测试代码

1
2
3
4
5
6
7
8
9
10
11
@Test
public void demoIni(){
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.createInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");
subject.login(token);
org.junit.Assert.assertEquals(true,subject.isAuthenticated());
subject.logout();
}

配置文件shiro.ini

1
2
[users]
admin=123456

理解

由配置文件,生成密码默认的密码验证器。
通过subject来验证密码是否正确

自定义Realm(域)示例

自己定义Realm

写明如何去验证,及支持的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MyRealm implements Realm {
@Override
public String getName() {
return "MyRealm";
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
if (!username.equals("admin")) {
throw new UnknownAccountException();
}
if (!password.equals("321321")) {
throw new IncorrectCredentialsException();
}
return new SimpleAuthenticationInfo(username, password, getName());
}
}

配置文件

shiro-realm.ini用来指明securityManager中对验证对象

1
2
3
[main]
myrealm=com.example.testshiro.MyRealm
securityManager.realms=$myrealm

测试用例

1
2
3
4
5
6
7
8
9
10
11
@Test
public void demoCustomRealm(){
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");
SecurityManager securityManager=factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject=SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken("admin","321321");
subject.login(token);
org.junit.Assert.assertEquals(true,subject.isAuthenticated());
subject.logout();
}

jdbc realm

依赖的pom文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--jdbcrealm依赖 start-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.3</version>
</dependency>
<!--jdbcrealm依赖 end-->

配置文件

shiro-jdbc-realm.ini 用于jdbcRealm的初始化

1
2
3
4
5
6
7
8
9
[main]
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
dataSource=com.alibaba.druid.pool.DruidDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/shirotest
dataSource.username=root
dataSource.password=root
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm

数据库表文件

shirotest.sql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
create table users (
id bigint auto_increment,
username varchar(100),
password varchar(100),
password_salt varchar(100),
constraint pk_users primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_users_username on users(username);

create table user_roles(
id bigint auto_increment,
username varchar(100),
role_name varchar(100),
constraint pk_user_roles primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_user_roles on user_roles(username, role_name);

create table roles_permissions(
id bigint auto_increment,
role_name varchar(100),
permission varchar(100),
constraint pk_roles_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_roles_permissions on roles_permissions(role_name, permission);

insert into users(username,password)values('admin','123');

单元测试代码

1
2
3
4
5
6
7
8
9
10
11
@Test
public void demoJdbcRealm(){
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");
SecurityManager securityManager=factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject=SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken("admin","123");
subject.login(token);
org.junit.Assert.assertEquals(true,subject.isAuthenticated());
subject.logout();
}

一点心得

  • IniSecurityManagerFactory是用org.apache.shiro.config.ReflectionBuilder这个工具把配置文件中的配置实例化的
  • 默认的Realm、自己定义的Realm、jdbc的Realm,使用工厂方式,把实际需要的Realm构造出来。
  • 验证主体是subject,这些框架看看代码,了解下结构,还是比较好掌握的。

参考