您的位置:首页 > 其它

Shiro学习随笔【二】身份认证

2017-09-14 13:32 357 查看
一、身份认证也就是提供相应的凭证证明你是用户本人,通常是指用户名和密码,在Shiro中用户需要体用Principals(身份)、Credentials(证明)给shiro,从而能够验证用户的身份。

Principals:身份,即主题的标识属性,可以有多个如邮箱、手机号、用户名等,但是只能有一个主身份标识。

Credentials:证明/凭证,即用户的密码或者数字证书。

二、用户的登录和退出

首先新增配置文件shiro.ini,在配置文件中新增:zhang=123

验证用户登录和退出的代码如下:

package shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @Description:TODO
* @version 1.0
* @since JDK1.7
* @author yaomy
* @company xxxxxxxxxxxxxx
* @copyright (c) 2017 yaomy Co'Ltd Inc. All rights reserved.
* @date 2017年9月13日 下午4:37:09
*/
public class LoginOutDemo {
private static final transient Logger log = LoggerFactory.getLogger(LoginOutDemo.class);
public static void main(String[] args) {
//获取SecurityManager安全管理器工厂类,此处使用shiro.ini文件进行初始化
Factory<SecurityManager> factory = new IniSecurityManagerFactory("conf/shiro.ini");
//获取SecurityManager安全管理器实例,并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//获取主题
Subject subject = SecurityUtils.getSubject();
//创建用户名密码身份验证token(即:用户身份/凭证)
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
token.setRememberMe(true);
try{
//登录,即身份验证
subject.login(token);
log.info("登录成功");
} catch(AuthenticationException e){
log.info("身份验证失败"+e);
}

subject.logout();
}
}


执行的结果如下:
11:50:11,085 INFO ~ Enabling session validation scheduler...
11:50:11,139 INFO ~ 登录成功

以上代码是从配置文件中读取用户的信息,下面接着讲从单个Realm中读取用户数据

三、Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

自定义Realm实现:

package shiro;

import java.util.Arrays;

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

/**
* 单个Realm配置
* @Description:域,Shiro从从Realm获取安全数据(如用户、角色、权限)
* @version 1.0
* @since JDK1.7
* @author yaomy
* @company xxxxxxxxxxxxxx
* @copyright (c) 2017 yaomy Co'Ltd Inc. All rights reserved.
* @date 2017年9月13日 下午6:03:43
*/
public class MyRealm implements Realm{

/**
*
* @Description:返回唯一的Realm名字
* @author yaomy
* @date 2017年9月13日 下午6:04:21
*/
@Override
public String getName() {
// TODO Auto-generated method stub
return "myrealm";
}

/**
*
* @Description:判断此Realm是否支持此token
* @author yaomy
* @date 2017年9月13日 下午6:04:43
*/
@Override
public boolean supports(AuthenticationToken token) {
// 仅支持UsernamePasswordToken类型的token
return token instanceof UsernamePasswordToken;
}

/**
*
* @Description:根据token获取认证信息
* @author yaomy
* @date 2017年9月13日 下午6:05:20
*/
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
String username = (String)token.getPrincipal();//用户名(认证)
String password = new String((char[])token.getCredentials());//用
ddfa
户密码(凭证)

if(!username.equals("zhang")){
throw new UnknownAccountException();
}
if(!password.equals("123")){
throw new IncorrectCredentialsException();
}
return new SimpleAuthenticationInfo(username, password, getName());
}

}


定义配置文件shiro-realm.ini
myrealm=shiro.MyRealm
securityManager.realms=$myrealm

测试Realm代码如下:
package shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* http://jinnianshilongnian.iteye.com/blog/2019547 * @Description:TODO
* @version 1.0
* @since JDK1.7
* @author yaomy
* @company xxxxxxxxxxxxxx
* @copyright (c) 2017 yaomy Co'Ltd Inc. All rights reserved.
* @date 2017年9月13日 下午4:37:09
*/
public class RealmDemo {
private static final transient Logger log = LoggerFactory.getLogger(RealmDemo.class);
public static void main(String[] args) {
//获取SecurityManager安全管理器工厂类,此处使用shiro.ini文件进行初始化
Factory<SecurityManager> factory = new IniSecurityManagerFactory("conf/shiro-realm.ini");
//获取SecurityManager安全管理器实例,并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);

//获取主题
Subject subject = SecurityUtils.getSubject();

//创建用户名密码身份验证token(即:用户身份/凭证)
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123", true);
try{
//登录,即身份验证
subject.login(token);
log.info("登录成功");
} catch(AuthenticationException e){
log.info("身份验证失败"+e);
}

subject.logout();
}
}

执行测试代码:

11:57:09,203 INFO ~ Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur.
11:57:09,213 INFO ~ Enabling session validation scheduler...
11:57:09,247 INFO ~ 登录成功


四、多个Realm

Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点,如果验证成功,将返回AuthenticationInfo验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的AuthenticationException实现。

SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:

FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;

AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;

AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。

ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。

配置文件shiro-realm.ini

#指定securityManager的authenticator实现
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
securityManager.authenticator=$authenticator

#指定securityManager.authenticator的authenticationStrategy
allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy

myrealm=shiro.MyRealm
myrealm2=shiro.MyRealm2
securityManager.realms=$myrealm,$myrealm2


测试代码:
package shiro;

import java.util.Arrays;

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

/**
* 单个Realm配置
* @Description:域,Shiro从从Realm获取安全数据(如用户、角色、权限)
* @version 1.0
* @since JDK1.7
* @author yaomy
* @company xxxxxxxxxxxxxx
* @copyright (c) 2017 yaomy Co'Ltd Inc. All rights reserved.
* @date 2017年9月13日 下午6:03:43
*/
public class MyRealm2 implements Realm{

/**
*
* @Description:返回唯一的Realm名字
* @author yaomy
* @date 2017年9月13日 下午6:04:21
*/
@Override
public String getName() {
// TODO Auto-generated method stub
return "myrealm2";
}

/**
*
* @Description:判断此Realm是否支持此token
* @author yaomy
* @date 2017年9月13日 下午6:04:43
*/
@Override
public boolean supports(AuthenticationToken token) {
// 仅支持UsernamePasswordToken类型的token
return token instanceof UsernamePasswordToken;
}

/**
*
* @Description:根据token获取认证信息
* @author yaomy
* @date 2017年9月13日 下午6:05:20
*/
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
String username = (String)token.getPrincipal();//用户名(认证)
String password = new String((char[])token.getCredentials());//用户密码(凭证)

if(!username.equals("zhang")){
throw new UnknownAccountException();
}
if(!password.equals("123")){
throw new IncorrectCredentialsException();
}
return new SimpleAuthenticationInfo(username, password, getName());
}

}


package shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* http://jinnianshilongnian.iteye.com/blog/2019547 * @Description:TODO
* @version 1.0
* @since JDK1.7
* @author yaomy
* @company xxxxxxxxxxxxxx
* @copyright (c) 2017 yaomy Co'Ltd Inc. All rights reserved.
* @date 2017年9月13日 下午4:37:09
*/
public class RealmDemo {
private static final transient Logger log = LoggerFactory.getLogger(RealmDemo.class);
public static void main(String[] args) {
//获取SecurityManager安全管理器工厂类,此处使用shiro.ini文件进行初始化
Factory<SecurityManager> factory = new IniSecurityManagerFactory("conf/shiro-realm.ini");
//获取SecurityManager安全管理器实例,并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);

//获取主题
Subject subject = SecurityUtils.getSubject();

//创建用户名密码身份验证token(即:用户身份/凭证)
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123", true);
try{
//登录,即身份验证
subject.login(token);
log.info("登录成功");
} catch(AuthenticationException e){
log.info("身份验证失败"+e);
}

subject.logout();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: