realm :域 –存放安全数据的地方。SecurityManager要验证用户的身份,就要从realm获取用户来验证用户的身份是否合法,还需要从realm获取用户的角色和权限来判断用户是否能进行操作。可以把realm看做成一个安全数据源(DataSource)。
需要实现org.apache.shiro.realm.Realm接口
string getName();//返回一个唯一的realm名字
boolean supports(AuthenticationToken token);//由此判断realm是否支持此token
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)throws AuthenticationException; //根据Token获取认证信息
自定义relam实现
public class MyRealm1 implements Realm {
@Override
public String getName() {
return "myrealm1";//返回一个realm名
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;//仅支持UsernamePasswordToken类型的token
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String)token.getPrincipal();//得到用户名
String password = new String((char[])token.getCredentials());//得到用户密码
if(!"zhang".equals(username)){
throw new UnknownAccountException();//身份验证失败
}
if(!"123".equals(password)){
throw new IncorrectCredentialsException();//密码验证失败
}
//如果身份认证验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(username,password,getName());
}
}
在ini 配置文件指定自定义 Realm 实现 (shiro-realm.ini)
[main]
#声明一个realm
myRealm1=org.wct.shiro.realm.MyRealm1
#指定securityManager的realms实现
securityManager.realms=$myRealm1
测试用例如下
@Test
public void testShirorealm(){
//1.得到securityManager并实例化
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");
SecurityManager securityManager = factory.getInstance();
//2.绑定给SecurityUtils
SecurityUtils.setSecurityManager(securityManager);
//3.得到subject和进行用户身份验证的token
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");
try{
subject.login(token);
}catch (AuthenticationException e){
}
Boolean b = subject.isAuthenticated();
Assert.assertEquals(true,subject.isAuthenticated());//断言用户已经登录
subject.logout();
}
定义myrealm2
public class MyRealm2 implements Realm {
@Override
public String getName() {
return "myrealm2";
}
@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(!"wang".equals(username)){
throw new UnknownAccountException();
}
if (!"123".equals(password)){
throw new IncorrectCredentialsException();
}
return new SimpleAuthenticationInfo(username,password,getName());
}
}
在ini配置文件里配置(shiro-multi-realm.ini)
[main]
#声明一个realm
myRealm1=org.wct.shiro.realm.MyRealm1
myRealm2=org.wct.shiro.realm.MyRealm2
#指定securityManager的realms实现
securityManager.realms=$myRealm1,$myRealm2
securityManager 会按照 realms 指定的顺序进行身份认证。此处我们使用显示指定顺序的方式指定了 Realm 的顺序,如果删除 “securityManager.realms= myRealm1, m y R e a l m 1 , myRealm2”,那么securityManager 会按照 realm 声明的顺序进行使用(即无需设置 realms 属性,其会自动发现),当我们显示指定 realm 后,其他没有指定 realm 将被忽略,如 “securityManager.realms=$myRealm1”,那么 myRealm2 不会被自动设置进去。
测试代码
@Test
public void testShiroMultiRealm(){
//1.得到securityManager并实例化
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-multi-realm.ini");
SecurityManager securityManager = factory.getInstance();
//2.绑定给SecurityUtils
SecurityUtils.setSecurityManager(securityManager);
//3.得到subject和进行用户身份验证的token
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("wang","123");
try{
subject.login(token);
}catch (AuthenticationException e){
}
Boolean b = subject.isAuthenticated();
Assert.assertEquals(true,subject.isAuthenticated());//断言用户已经登录
subject.logout();
}
数据库及依赖环境
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.25version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>0.2.23version>
dependency>
新建数据库shiro,具体的表和语句参照如下sql
drop database if exists shiro;
create database shiro;
use shiro;
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('zhang','123');
配置文件ini(shiro-jdbc-realm)
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/shiro
dataSource.username=root
dataSource.password=*****
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm
测试类代码如下:
@Test
public void testShiroJdbcRealm(){
//1.得到securityManager并实例化
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");
SecurityManager securityManager = factory.getInstance();
//2.绑定给SecurityUtils
SecurityUtils.setSecurityManager(securityManager);
//3.得到subject和进行用户身份验证的token
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");
try{
subject.login(token);
}catch (AuthenticationException e){
}
Boolean b = subject.isAuthenticated();
Assert.assertEquals(true,subject.isAuthenticated());//断言用户已经登录
subject.logout();
}