原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398
根据下载的pdf学习。
第二十一章 授予身份与切换身份(一)
1.使用场景
某个领导因为某些原因不能访问一些网站,他想把这个网站上的工作委托给秘书,但是他又不想提供账户、密码。此时可以使用shiro的 RunAs 功能。
RunAs:允许一个用户假装为另一个用户(如果获得了允许)的身份进行访问。
注意,本章代码基于《第十六章 综合实例》,详细的数据模型及基本流程见该章。
2.表及数据
请运行 shiro-example-chapter21/sql/ shiro-schema.sql 表结构
请运行 shiro-example-chapter21/sql/ shiro-data.sql 数据
drop table if exists sys_user;
drop table if exists sys_organization;
drop table if exists sys_resource;
drop table if exists sys_role;
drop table if exists sys_user_runas; create table sys_user (
id bigint auto_increment,
organization_id bigint,
username varchar(100),
password varchar(100),
salt varchar(100),
role_ids varchar(100),
locked bool default false,
constraint pk_sys_user primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_sys_user_username on sys_user(username);
create index idx_sys_user_organization_id on sys_user(organization_id); create table sys_organization (
id bigint auto_increment,
name varchar(100),
parent_id bigint,
parent_ids varchar(100),
available bool default false,
constraint pk_sys_organization primary key(id)
) charset=utf8 ENGINE=InnoDB;
create index idx_sys_organization_parent_id on sys_organization(parent_id);
create index idx_sys_organization_parent_ids on sys_organization(parent_ids); create table sys_resource (
id bigint auto_increment,
name varchar(100),
type varchar(50),
url varchar(200),
parent_id bigint,
parent_ids varchar(100),
permission varchar(100),
available bool default false,
constraint pk_sys_resource primary key(id)
) charset=utf8 ENGINE=InnoDB;
create index idx_sys_resource_parent_id on sys_resource(parent_id);
create index idx_sys_resource_parent_ids on sys_resource(parent_ids); create table sys_role (
id bigint auto_increment,
role varchar(100),
description varchar(100),
resource_ids varchar(100),
available bool default false,
constraint pk_sys_role primary key(id)
) charset=utf8 ENGINE=InnoDB;
create index idx_sys_role_resource_ids on sys_role(resource_ids); create table sys_user_runas (
from_user_id bigint,
to_user_id bigint,
constraint pk_sys_user_runas primary key(from_user_id, to_user_id)
) charset=utf8 ENGINE=InnoDB;
shiro-schema.sql
DELIMITER ;
delete from sys_user;
delete from sys_role;
delete from sys_resource;
delete from sys_organization;
delete from sys_user_runas; insert into sys_user values(1,1,'admin','d3c59d25033dbf980d29554025c23a75','8d78869f470951332959580424d4bf4f', '1', false);
insert into sys_user values(2,1,'zhang','c6a02f6c9a5aaf311ec94009b6b024d0','588ae709311808bd7e5fade1c84407c7', '1', false);
insert into sys_user values(3,1,'wang','2e6f83bdaef108d4f23b2a1f2b9928cc','bd647b15f6724ea711272c4a3c6d16c0', '1', false); insert into sys_organization values(1, '总公司', 0, '0/', true);
insert into sys_organization values(2, '分公司1', 1, '0/1/', true);
insert into sys_organization values(3, '分公司2', 1, '0/1/', true);
insert into sys_organization values(4, '分公司11', 2, '0/1/2/', true); insert into sys_resource values(1, '资源', 'menu', '', 0, '0/', '', true); insert into sys_resource values(11, '组织机构管理', 'menu', '/organization', 1, '0/1/', 'organization:*', true);
insert into sys_resource values(12, '组织机构新增', 'button', '', 11, '0/1/11/', 'organization:create', true);
insert into sys_resource values(13, '组织机构修改', 'button', '', 11, '0/1/11/', 'organization:update', true);
insert into sys_resource values(14, '组织机构删除', 'button', '', 11, '0/1/11/', 'organization:delete', true);
insert into sys_resource values(15, '组织机构查看', 'button', '', 11, '0/1/11/', 'organization:view', true); insert into sys_resource values(21, '用户管理', 'menu', '/user', 1, '0/1/', 'user:*', true);
insert into sys_resource values(22, '用户新增', 'button', '', 21, '0/1/21/', 'user:create', true);
insert into sys_resource values(23, '用户修改', 'button', '', 21, '0/1/21/', 'user:update', true);
insert into sys_resource values(24, '用户删除', 'button', '', 21, '0/1/21/', 'user:delete', true);
insert into sys_resource values(25, '用户查看', 'button', '', 21, '0/1/21/', 'user:view', true); insert into sys_resource values(31, '资源管理', 'menu', '/resource', 1, '0/1/', 'resource:*', true);
insert into sys_resource values(32, '资源新增', 'button', '', 31, '0/1/31/', 'resource:create', true);
insert into sys_resource values(33, '资源修改', 'button', '', 31, '0/1/31/', 'resource:update', true);
insert into sys_resource values(34, '资源删除', 'button', '', 31, '0/1/31/', 'resource:delete', true);
insert into sys_resource values(35, '资源查看', 'button', '', 31, '0/1/31/', 'resource:view', true); insert into sys_resource values(41, '角色管理', 'menu', '/role', 1, '0/1/', 'role:*', true);
insert into sys_resource values(42, '角色新增', 'button', '', 41, '0/1/41/', 'role:create', true);
insert into sys_resource values(43, '角色修改', 'button', '', 41, '0/1/41/', 'role:update', true);
insert into sys_resource values(44, '角色删除', 'button', '', 41, '0/1/41/', 'role:delete', true);
insert into sys_resource values(45, '角色查看', 'button', '', 41, '0/1/41/', 'role:view', true); insert into sys_role values(1, 'admin', '超级管理员', '11,21,31,41', true);
shiro-data.sql
增加的sql语句:
drop table if exists sys_user_runas;
create table sys_user_runas (
from_user_id bigint,
to_user_id bigint,
constraint pk_sys_user_runas primary key(from_user_id, to_user_id)
) charset=utf8 ENGINE=InnoDB;
3.实体entity
package com.github.zhangkaitao.shiro.chapter21.entity;
import java.io.Serializable; public class Organization implements Serializable {
private Long id; //编号
private String name; //组织机构名称
private Long parentId; //父编号
private String parentIds; //父编号列表,如1/2/
private Boolean available = Boolean.FALSE; //getter、setter略 public boolean isRootNode() {
return parentId == 0;
} public String makeSelfAsParentIds() {
return getParentIds() + getId() + "/";
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; Organization that = (Organization) o; if (id != null ? !id.equals(that.id) : that.id != null) return false; return true;
} @Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
} @Override
public String toString() {
return "Organization{" +
"id=" + id +
", name='" + name + '\'' +
", parentId=" + parentId +
", parentIds='" + parentIds + '\'' +
", available=" + available +
'}';
}
}
Organization
package com.github.zhangkaitao.shiro.chapter21.entity;
import java.io.Serializable; public class Resource implements Serializable {
private Long id; //编号
private String name; //资源名称
private ResourceType type = ResourceType.menu; //资源类型
private String url; //资源路径
private String permission; //权限字符串
private Long parentId; //父编号
private String parentIds; //父编号列表
private Boolean available = Boolean.FALSE; public static enum ResourceType {
menu("菜单"), button("按钮"); private final String info;
private ResourceType(String info) {
this.info = info;
} public String getInfo() {
return info;
}
} //getter、setter略 public boolean isRootNode() {
return parentId == 0;
} public String makeSelfAsParentIds() {
return getParentIds() + getId() + "/";
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; Resource resource = (Resource) o; if (id != null ? !id.equals(resource.id) : resource.id != null) return false; return true;
} @Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
} @Override
public String toString() {
return "Resource{" +
"id=" + id +
", name='" + name + '\'' +
", type=" + type +
", permission='" + permission + '\'' +
", parentId=" + parentId +
", parentIds='" + parentIds + '\'' +
", available=" + available +
'}';
}
}
Resource
package com.github.zhangkaitao.shiro.chapter21.entity; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; public class Role implements Serializable {
private Long id; //编号
private String role; //角色标识 程序中判断使用,如"admin"
private String description; //角色描述,UI界面显示使用
private List<Long> resourceIds; //拥有的资源
private Boolean available = Boolean.FALSE; //是否可用,如果不可用将不会添加给用户 public Role() {
} public Role(String role, String description, Boolean available) {
this.role = role;
this.description = description;
this.available = available;
} //getter、setter略
public List<Long> getResourceIds() {
if(resourceIds == null) {
resourceIds = new ArrayList<Long>();
}
return resourceIds;
} public void setResourceIds(List<Long> resourceIds) {
this.resourceIds = resourceIds;
} public String getResourceIdsStr() {
if(CollectionUtils.isEmpty(resourceIds)) {
return "";
}
StringBuilder s = new StringBuilder();
for(Long resourceId : resourceIds) {
s.append(resourceId);
s.append(",");
}
return s.toString();
} public void setResourceIdsStr(String resourceIdsStr) {
if(StringUtils.isEmpty(resourceIdsStr)) {
return;
}
String[] resourceIdStrs = resourceIdsStr.split(",");
for(String resourceIdStr : resourceIdStrs) {
if(StringUtils.isEmpty(resourceIdStr)) {
continue;
}
getResourceIds().add(Long.valueOf(resourceIdStr));
}
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; Role role = (Role) o; if (id != null ? !id.equals(role.id) : role.id != null) return false; return true;
} @Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
} @Override
public String toString() {
return "Role{" +
"id=" + id +
", role='" + role + '\'' +
", description='" + description + '\'' +
", resourceIds=" + resourceIds +
", available=" + available +
'}';
}
}
Role
package com.github.zhangkaitao.shiro.chapter21.entity; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; public class User implements Serializable {
private Long id; //编号
private Long organizationId; //所属公司
private String username; //用户名
private String password; //密码
private String salt; //加密密码的盐
private List<Long> roleIds; //拥有的角色列表
private Boolean locked = Boolean.FALSE; public User() {
} public User(String username, String password) {
this.username = username;
this.password = password;
} //getter、setter略 public String getCredentialsSalt() {
return username + salt;
} public List<Long> getRoleIds() {
if(roleIds == null) {
roleIds = new ArrayList<Long>();
}
return roleIds;
} public void setRoleIds(List<Long> roleIds) {
this.roleIds = roleIds;
} public String getRoleIdsStr() {
if(CollectionUtils.isEmpty(roleIds)) {
return "";
}
StringBuilder s = new StringBuilder();
for(Long roleId : roleIds) {
s.append(roleId);
s.append(",");
}
return s.toString();
} public void setRoleIdsStr(String roleIdsStr) {
if(StringUtils.isEmpty(roleIdsStr)) {
return;
}
String[] roleIdStrs = roleIdsStr.split(",");
for(String roleIdStr : roleIdStrs) {
if(StringUtils.isEmpty(roleIdStr)) {
continue;
}
getRoleIds().add(Long.valueOf(roleIdStr));
}
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (id != null ? !id.equals(user.id) : user.id != null) return false; return true;
} @Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
} @Override
public String toString() {
return "User{" +
"id=" + id +
", organizationId=" + organizationId +
", username='" + username + '\'' +
", password='" + password + '\'' +
", salt='" + salt + '\'' +
", roleIds=" + roleIds +
", locked=" + locked +
'}';
}
}
User
这都是前面章节的内容了。重点是UserRunAs。该实体定义了授予身份账号(A)与被授予身份账号(B)的关系。B将假装为A进行访问。
package com.github.zhangkaitao.shiro.chapter21.entity; import java.io.Serializable; public class UserRunAs implements Serializable {
private Long fromUserId;//授予身份帐号
private Long toUserId;//被授予身份帐号
//getter、setter略 @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; UserRunAs userRunAs = (UserRunAs) o; if (fromUserId != null ? !fromUserId.equals(userRunAs.fromUserId) : userRunAs.fromUserId != null) return false;
if (toUserId != null ? !toUserId.equals(userRunAs.toUserId) : userRunAs.toUserId != null) return false; return true;
} @Override
public int hashCode() {
int result = fromUserId != null ? fromUserId.hashCode() : 0;
result = 31 * result + (toUserId != null ? toUserId.hashCode() : 0);
return result;
} @Override
public String toString() {
return "UserRunAs{" +
"fromUserId=" + fromUserId +
", toUserId=" + toUserId +
'}';
}
}
4.Service层
其他的就只放接口类了,runas相关的会放上实现类。
package com.github.zhangkaitao.shiro.chapter21.service; import com.github.zhangkaitao.shiro.chapter21.entity.Organization;
import java.util.List; public interface OrganizationService { public Organization createOrganization(Organization organization);
public Organization updateOrganization(Organization organization);
public void deleteOrganization(Long organizationId); Organization findOne(Long organizationId);
List<Organization> findAll(); Object findAllWithExclude(Organization excludeOraganization); void move(Organization source, Organization target);
}
OrganizationService
package com.github.zhangkaitao.shiro.chapter21.service; import com.github.zhangkaitao.shiro.chapter21.entity.Resource;
import java.util.List;
import java.util.Set; public interface ResourceService { public Resource createResource(Resource resource);
public Resource updateResource(Resource resource);
public void deleteResource(Long resourceId); Resource findOne(Long resourceId);
List<Resource> findAll(); /**
* 得到资源对应的权限字符串
* @param resourceIds
* @return
*/
Set<String> findPermissions(Set<Long> resourceIds); /**
* 根据用户权限得到菜单
* @param permissions
* @return
*/
List<Resource> findMenus(Set<String> permissions);
}
ResourceService
package com.github.zhangkaitao.shiro.chapter21.service; import com.github.zhangkaitao.shiro.chapter21.entity.Role;
import java.util.List;
import java.util.Set; public interface RoleService { public Role createRole(Role role);
public Role updateRole(Role role);
public void deleteRole(Long roleId); public Role findOne(Long roleId);
public List<Role> findAll(); /**
* 根据角色编号得到角色标识符列表
* @param roleIds
* @return
*/
Set<String> findRoles(Long... roleIds); /**
* 根据角色编号得到权限字符串列表
* @param roleIds
* @return
*/
Set<String> findPermissions(Long[] roleIds);
}
RoleService
package com.github.zhangkaitao.shiro.chapter21.service; import com.github.zhangkaitao.shiro.chapter21.entity.User;
import java.util.List;
import java.util.Set; public interface UserService { public User createUser(User user);
public User updateUser(User user);
public void deleteUser(Long userId); public void changePassword(Long userId, String newPassword); User findOne(Long userId);
List<User> findAll();
public User findByUsername(String username); /**
* 根据用户名查找其角色
* @param username
* @return
*/
public Set<String> findRoles(String username); /**
* 根据用户名查找其权限
* @param username
* @return
*/
public Set<String> findPermissions(String username); }
UserService
RunAsService:
package com.github.zhangkaitao.shiro.chapter21.service;
import java.util.List; public interface UserRunAsService { public void grantRunAs(Long fromUserId, Long toUserId);//授予身份
public void revokeRunAs(Long fromUserId, Long toUserId);//回收身份
public boolean exists(Long fromUserId, Long toUserId);//关系存在
public List<Long> findFromUserIds(Long toUserId);//查找
public List<Long> findToUserIds(Long fromUserId);//查找
}
UserRunAsServiceImpl:
package com.github.zhangkaitao.shiro.chapter21.service; import com.github.zhangkaitao.shiro.chapter21.dao.UserRunAsDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List; @Service
public class UserRunAsServiceImpl implements UserRunAsService {
@Autowired
private UserRunAsDao userRunAsDao;
@Override
public void grantRunAs(Long fromUserId, Long toUserId) {
userRunAsDao.grantRunAs(fromUserId, toUserId);
} @Override
public void revokeRunAs(Long fromUserId, Long toUserId) {
userRunAsDao.revokeRunAs(fromUserId, toUserId);
} @Override
public boolean exists(Long fromUserId, Long toUserId) {
return userRunAsDao.exists(fromUserId, toUserId);
} @Override
public List<Long> findFromUserIds(Long toUserId) {
return userRunAsDao.findFromUserIds(toUserId);
} @Override
public List<Long> findToUserIds(Long fromUserId) {
return userRunAsDao.findToUserIds(fromUserId);
}
}
5.Dao层
同样,其他的几个就只放接口了。
package com.github.zhangkaitao.shiro.chapter21.dao; import com.github.zhangkaitao.shiro.chapter21.entity.Organization;
import java.util.List; public interface OrganizationDao { public Organization createOrganization(Organization organization);
public Organization updateOrganization(Organization organization);
public void deleteOrganization(Long organizationId); Organization findOne(Long organizationId);
List<Organization> findAll(); List<Organization> findAllWithExclude(Organization excludeOraganization); void move(Organization source, Organization target);
}
OrganizationDao
package com.github.zhangkaitao.shiro.chapter21.dao; import com.github.zhangkaitao.shiro.chapter21.entity.Resource;
import java.util.List; public interface ResourceDao { public Resource createResource(Resource resource);
public Resource updateResource(Resource resource);
public void deleteResource(Long resourceId); Resource findOne(Long resourceId);
List<Resource> findAll(); }
ResourceDao
package com.github.zhangkaitao.shiro.chapter21.dao; import com.github.zhangkaitao.shiro.chapter21.entity.Role;
import java.util.List; public interface RoleDao { public Role createRole(Role role);
public Role updateRole(Role role);
public void deleteRole(Long roleId); public Role findOne(Long roleId);
public List<Role> findAll();
}
RoleDao
package com.github.zhangkaitao.shiro.chapter21.dao; import com.github.zhangkaitao.shiro.chapter21.entity.User;
import java.util.List; public interface UserDao { public User createUser(User user);
public User updateUser(User user);
public void deleteUser(Long userId); User findOne(Long userId);
List<User> findAll();
User findByUsername(String username); }
UserDao
UserRunAsDao:
package com.github.zhangkaitao.shiro.chapter21.dao; import java.util.List; public interface UserRunAsDao { public void grantRunAs(Long fromUserId, Long toUserId);
public void revokeRunAs(Long fromUserId, Long toUserId); public boolean exists(Long fromUserId, Long toUserId); public List<Long> findFromUserIds(Long toUserId);
public List<Long> findToUserIds(Long fromUserId); }
UserRunAsDaoImpl:
package com.github.zhangkaitao.shiro.chapter21.dao; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List; @Repository
public class UserRunAsDaoImpl implements UserRunAsDao { @Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void grantRunAs(Long fromUserId, Long toUserId) {
String sql = "insert into sys_user_runas(from_user_id, to_user_id) values (?,?)";
if(!exists(fromUserId, toUserId)) {
jdbcTemplate.update(sql, fromUserId, toUserId);
}
} public boolean exists(Long fromUserId, Long toUserId) {
String sql = "select count(1) from sys_user_runas where from_user_id=? and to_user_id=?";
return jdbcTemplate.queryForObject(sql, Integer.class, fromUserId, toUserId) != 0;
} @Override
public void revokeRunAs(Long fromUserId, Long toUserId) {
String sql = "delete from sys_user_runas where from_user_id=? and to_user_id=?";
jdbcTemplate.update(sql, fromUserId, toUserId);
} @Override
public List<Long> findFromUserIds(Long toUserId) {
String sql = "select from_user_id from sys_user_runas where to_user_id=?";
return jdbcTemplate.queryForList(sql, Long.class, toUserId);
} @Override
public List<Long> findToUserIds(Long fromUserId) {
String sql = "select to_user_id from sys_user_runas where from_user_id=?";
return jdbcTemplate.queryForList(sql, Long.class, fromUserId);
}
}
6.Realm
package com.github.zhangkaitao.shiro.chapter21.realm; import com.github.zhangkaitao.shiro.chapter21.entity.User;
import com.github.zhangkaitao.shiro.chapter21.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired; public class UserRealm extends AuthorizingRealm { @Autowired
private UserService userService; @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String)principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(userService.findRoles(username));
authorizationInfo.setStringPermissions(userService.findPermissions(username));
return authorizationInfo;
} @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); User user = userService.findByUsername(username); if(user == null) {
throw new UnknownAccountException();//没找到帐号
} if(Boolean.TRUE.equals(user.getLocked())) {
throw new LockedAccountException(); //帐号锁定
} //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user.getUsername(), //用户名
user.getPassword(), //密码
ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
getName() //realm name
);
return authenticationInfo;
} @Override
public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
super.clearCachedAuthorizationInfo(principals);
} @Override
public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
super.clearCachedAuthenticationInfo(principals);
} @Override
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
} public void clearAllCachedAuthorizationInfo() {
getAuthorizationCache().clear();
} public void clearAllCachedAuthenticationInfo() {
getAuthenticationCache().clear();
} public void clearAllCache() {
clearAllCachedAuthenticationInfo();
clearAllCachedAuthorizationInfo();
} }
UserRealm
package com.github.zhangkaitao.shiro.chapter21.credentials; import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import java.util.concurrent.atomic.AtomicInteger; public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher { private Cache<String, AtomicInteger> passwordRetryCache; public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
passwordRetryCache = cacheManager.getCache("passwordRetryCache");
} @Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
String username = (String)token.getPrincipal();
//retry count + 1
AtomicInteger retryCount = passwordRetryCache.get(username);
if(retryCount == null) {
retryCount = new AtomicInteger(0);
passwordRetryCache.put(username, retryCount);
}
if(retryCount.incrementAndGet() > 5) {
//if retry count > 5 throw
throw new ExcessiveAttemptsException();
} boolean matches = super.doCredentialsMatch(token, info);
if(matches) {
//clear retry count
passwordRetryCache.remove(username);
}
return matches;
}
}
RetryLimitHashedCredentialsMatcher
7.配置文件
略。
8.其他类
略。
由上可知,添加的东西有:
table:sys_user_runas
entity:UserRunAs
service:UserRunAsService、UserRunAsServiceImpl
dao:UserRunAsDao、UserRunAsDaoImpl
有daoImpl中的代码可知,它只是处理表sys_user_runas的一些基本增删改查操作。那么究竟是如何实现B可以嫁接A的身份进行呢?
请看:2017.2.15 开涛shiro教程-第二十一章-授予身份与切换身份(二) controller