多realm配置
public class MyRealm1 implements Realm {
public String getName() {
return "myrealm1";
}
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
}
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());
}
}
public class MyRealm2 implements Realm {
public String getName() {
return "myrealm2";
}
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
}
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(); //如果密码错误
}
//如果身份认证验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(username, password, getName());
}
}
[main]
#声明一个realm
myRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1
myRealm2=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm2
#指定securityManager的realms实现
securityManager.realms=$myRealm1,$myRealm2
securityManege会按照realm指定顺序进行身份验证,没有指定(securityManager.realms=myRealm1,myRealm2)也可以,那就会按照申明顺序进行使用。当显示指定realm后,其他没有被指定realm会被忽略,如:securityManage.realms=$myRealm1,那么myRealm2就不会被设置进realms。
@Test
public void testCustomMultiRealm() {
//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager> factory =
new IniSecurityManagerFactory("classpath:shiro-multi-realm.ini");
//2、得到SecurityManager实例 并绑定给SecurityUtils
org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("wang", "123");
try {
//4、登录,即身份验证
subject.login(token);
} catch (AuthenticationException e) {
//5、身份验证失败
e.printStackTrace();
}
Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录
//6、退出
subject.logout();
}
jdbcRealm使用
[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/shiro
dataSource.username=root
dataSource.password=root
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm
测试代码同上
问题记录:
当使用身份凭证登录后,再获取token信息时,如何设置token中放置的内容?
查看JdbcRealm类源码,可以看到doGetAuthenticationInfo(AuthenticationToken token)方法返回一个SimpleAuthenticationInfo info= new SimpleAuthenticationInfo(username, password.toCharArray(), this.getName());故而token中只放了username。
下面这个自定义realm类,在内部查询数据库,综合了自定义realm与jdbcRealm。
public class SampleRealm extends AuthorizingRealm {
@Autowired
UUserService userService;
@Autowired
PermissionService permissionService;
@Autowired
RoleService roleService;
public SampleRealm() {
super();
}
/**
* 认证信息,主要针对用户登录,
*/
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authcToken) throws AuthenticationException {
ShiroToken token = (ShiroToken) authcToken;
UUser user = userService.login(token.getUsername(), token.getPswd());
if (null == user) {
throw new AccountException("帐号或密码不正确!");
/**
* 如果用户的status为禁用。那么就抛出<code>DisabledAccountException</code>
*/
} else if (UUser._0.equals(user.getStatus())) {
throw new DisabledAccountException("帐号已经禁止登录!");
} else {
//更新登录时间 last login time
user.setLastLoginTime(new Date());
userService.updateByPrimaryKeySelective(user);
}
return new SimpleAuthenticationInfo(user, user.getPswd(), getName());
}
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
Long userId = TokenManager.getUserId();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//根据用户ID查询角色(role),放入到Authorization里。
Set<String> roles = roleService.findRoleByUserId(userId);
info.setRoles(roles);
//根据用户ID查询权限(permission),放入到Authorization里。
Set<String> permissions = permissionService.findPermissionByUserId(userId);
info.setStringPermissions(permissions);
return info;
}
/**
* 清空当前用户权限信息
*/
public void clearCachedAuthorizationInfo() {
PrincipalCollection principalCollection = SecurityUtils.getSubject().getPrincipals();
SimplePrincipalCollection principals = new SimplePrincipalCollection(
principalCollection, getName());
super.clearCachedAuthorizationInfo(principals);
}
/**
* 指定principalCollection 清除
*/
public void clearCachedAuthorizationInfo(PrincipalCollection principalCollection) {
SimplePrincipalCollection principals = new SimplePrincipalCollection(
principalCollection, getName());
super.clearCachedAuthorizationInfo(principals);
}
}
关键点:doGetAuthenticationInfo(AuthenticationToken token)方法的返回值
return new SimpleAuthenticationInfo(user, user.getPswd(), getName());所以返回的token是一个user实体。