黑马程序员技术交流社区

标题: 【上海校区】Shiro学习笔记整理--身份校验之Realm域 [打印本页]

作者: shjava    时间: 2017-10-19 17:07
标题: 【上海校区】Shiro学习笔记整理--身份校验之Realm域
本帖最后由 shjava 于 2017-10-26 15:23 编辑

域,ShiroRealm获取安全数据(用户,角色,权限)。
SecurityManager校验用户身份,会从Ream中获取数据进行比较确定用户身份是否合法。也需要从Realm中获取用户是否有对应用户和权限进行操作。
我们可以把Realm当作数据源。从而获取用户校验和授权功能
Realm接口的代码:
[Java] 纯文本查看 复制代码
publicinterface Realm {

       String getName();//
返回一个唯一的 Realm 名字

       booleansupports(AuthenticationToken token);//
判断此Realm 是否支持此 Token

       AuthenticationInfo getAuthenticationInfo(AuthenticationTokentoken) throws AuthenticationException;//
根据Token 获取认证信息

}


自定义单Realm的配置:
【演示】:
1、新建maven子项目
[Java] 纯文本查看 复制代码
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>


2、创建自定义Realm,实现Realm接口,重写方法
[Java] 纯文本查看 复制代码
packagecn.oriki.shiro.realm;

import org.apache.shiro.authc.AuthenticationException;
importorg.apache.shiro.authc.AuthenticationInfo;
importorg.apache.shiro.authc.AuthenticationToken;
importorg.apache.shiro.authc.IncorrectCredentialsException;
importorg.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
importorg.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.Realm;

public class MyRealm implements Realm {

@Override
public String getName() {
return "myRealm";
}

@Override
public boolean supports(AuthenticationTokentoken) {
//
仅支持UsernamePasswordToken 类型的Token
return token instanceof UsernamePasswordToken;
}

@Override
public AuthenticationInfogetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException{
String username = (String) token.getPrincipal();//
得到用户名
String password = new String((char[])token.getCredentials()); //
得到密码
if (!"zhangsan".equals(username)) {
throw new UnknownAccountException(); //
如果用户名错误
}
if (!"123".equals(password)) {
throw new IncorrectCredentialsException(); //
如果密码错误
}
//
如果身份认证验证成功,返回一个AuthenticationInfo 实现;
return new SimpleAuthenticationInfo(username,password, getName());
}
}


3、配置shiro-realm.ini配置文件
[Java] 纯文本查看 复制代码
#声明一个 realm
myRealm=cn.oriki.shiro.realm.MyRealm
#
指定securityManager realms 实现
securityManager.realms=$myRealm


4、测试
[Java] 纯文本查看 复制代码
packagecn.oriki.shiro.test;

import org.apache.shiro.SecurityUtils;
importorg.apache.shiro.authc.AuthenticationException;
importorg.apache.shiro.authc.UsernamePasswordToken;
importorg.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

import junit.framework.Assert;

public class ShiroTest {
@Test
public void testHelloworld() {
// 1
、获取SecurityManager 工厂,此处使用Ini 配置文件初始化 SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager>factory = new IniSecurityManagerFactory(
"classpath:shiro-realm.ini");

// 2
、得到SecurityManager 实例并绑定给 SecurityUtils
org.apache.shiro.mgt.SecurityManagersecurityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);

// 3
、得到Subject 及创建用户名/密码身份验证 Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();

UsernamePasswordToken token = newUsernamePasswordToken("zhangsan", "123");
// 4
、登录,即身份验证
try {
subject.login(token);
} catch (AuthenticationException e) {
//
身份验证失败
e.printStackTrace();
}

// 5
、断言用户已经登陆
Assert.assertEquals(true,subject.isAuthenticated());

// 6
、退出
subject.logout();
}

}


3、自定义多Realm的配置:
和单配置的基本一样,但是我们在shiro-realm.ini的配置,多添加一个自定义域
shiro-realm.ini
[Java] 纯文本查看 复制代码
#声明多个 realm
myRealm=cn.oriki.shiro.realm.MyRealm
myRealm2=cn.oriki.shiro.realm.MyRealm2

#
指定securityManager realms 实现
securityManager.realms=$myRealm,$myRealm2
securityManager会按照realms指定的顺序进行身份认证。


4shiro提供的Realm
file:///C:/Users/yst/AppData/Local/Temp/msohtmlclip1/01/clip_image001.png
以后一般继承 AuthorizingRealm(授权)即可;其继承了AuthenticatingRealm(即身份验证),而且也间接继承了CachingRealm(带有缓存实现)。其中主要默认实现如下:
org.apache.shiro.realm.text.IniRealm:[users]部分指定用户名/密码及其角色;[roles]部分指定角色即权限信息;
org.apache.shiro.realm.text.PropertiesRealm:user.username=password,role1,role2指定用户 /密码及其角色;role.role1=permission1,permission2 指定角色及权限信息;
org.apache.shiro.realm.jdbc.JdbcRealm:通过sql查询相应的信息,如“selectpasswordfrom users where username = ?”获取用户密码,“select password, password_saltfrom userswhere username = ?”获取用户密码及盐;“select role_name from user_roleswhereusername = ?” 获取用户角色;“select permission from roles_permissionswhere role_name= ?”获取角色对应的权限信息;也可以调用相应的api进行自定义sql;






5JdbcRealm的使用:
【演示】:
0、创建数据库
[SQL] 纯文本查看 复制代码
dropdatabase if exists db_shiro;
create database db_shiro;
use db_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 onusers(username);

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

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

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


1、新建maven工程,引入依赖
[Java] 纯文本查看 复制代码
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>0.2.23</version>
</dependency>


2、创建shiro-jdbcRealm.ini,编写配置
[Java] 纯文本查看 复制代码
#指定使用JdbcRealm
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm

#
配置datasource数据源
dataSource=com.alibaba.druid.pool.DruidDataSource

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/db_shiro
dataSource.username=root
dataSource.password=4869

#
JdbcRealm注入数据源
jdbcRealm.dataSource=$dataSource

securityManager.realms=$jdbcRealm


3、测试
[Java] 纯文本查看 复制代码
package cn.oriki.shiro.test;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
importorg.apache.shiro.authc.UsernamePasswordToken;
importorg.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Assert;
import org.junit.Test;

public class ShiroTest {
@Test
public void testHelloworld() {
// 1
、获取SecurityManager 工厂,此处使用Ini 配置文件初始化 SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager>factory = new IniSecurityManagerFactory(
"classpath:shiro-jdbcRealm.ini");

// 2
、得到SecurityManager 实例并绑定给SecurityUtils
org.apache.shiro.mgt.SecurityManagersecurityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);

// 3
、得到Subject 及创建用户名/密码身份验证 Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();

UsernamePasswordToken token = newUsernamePasswordToken("zhangsan", "123");
// 4
、登录,即身份验证
try {
subject.login(token);
} catch (AuthenticationException e) {
//
身份验证失败
e.printStackTrace();
}

// 5
、断言用户已经登陆
Assert.assertEquals(true,subject.isAuthenticated());

// 6
、退出
subject.logout();
}
}

















作者: buguniao    时间: 2017-10-19 18:49
好贴




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2