最近使用shiro做权限管理,想问下shiro中自定义的realm托管给spring,是单例好呢还是多例好?希望有大牛可以分享一下,如果能给出相关的文档,那就更感谢了。本菜更偏向使用单例,但是项目中配置的是多例,因此有这个疑惑,谢谢大家了
补充代码:
public class ShiroDbRealmService extends AuthorizingRealm {
/**
* 用户service接口
*/
private IUserService userService;
/**
* 日志打印
*/
private static Logger logger = LoggerFactory.getLogger(ShiroDbRealmService.class);
/**
* 支持什么类型的token
*/
@Override
public boolean supports(AuthenticationToken token) {
// TODO Auto-generated method stub
return super.supports(token);
}
/**
* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
throw new AuthorizationException("principals不能为空");
}
//多例的情况下,不同实例的getName()返回的值是不一样的
User user = (User) principals.fromRealm(getName()).iterator().next();
if (user == null) {
throw new UnknownAccountException("用户不存在");
}
SimpleAuthorizationInfo authorizationInfo = getAuthorizationInfoFromMem(user);
return authorizationInfo;
}
/**
* 从缓存中获取授权信息
*
* @return
*/
private SimpleAuthorizationInfo getAuthorizationInfoFromMem(User user) {
System.out.println("get author info...");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 从缓存中获取相应的信息
UserResource userResource = (UserResource) ShiroSession.getSessionInstance()
.getAttribute(LoginEnum.USER_AUTHOR_INFO.getKey());
// 如果缓存中没有,再次调用
if (userResource != null) {
// 转化
Map<String, Station> stationMap = userResource.getStationMap();
if (!stationMap.isEmpty()) {
Station station = stationMap
.get(ShiroSession.getSessionInstance().getAttribute(LoginEnum.USER_STATION_INFO.getKey()));
// TODO 解析岗位信息,角色,权限
List<Role> roleList = station.getRoleList();
for (Role role : roleList) {
info.addRole(role.getName());
List<Resource> resList = role.getResList();
for (Resource resource : resList) {
info.addStringPermission(resource.getPremsCode());
}
}
}
}
return info;
}
/**
* 登录信息和用户验证信息验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
throws AuthenticationException {
/* Subject subject = ShiroSession.getSubjectInstance(); */
UsernamePasswordCaptchaToken token = (UsernamePasswordCaptchaToken) authcToken;
// 校验验证码
if (doCaptchaValidate(token)) {
// 通过登录名去查询
User user = userService.selectUserByLoginName(token.getUsername());
if (user != null) {
return new SimpleAuthenticationInfo(user, (user.getPassword()).toLowerCase(), this.getName());
}
else {
throw new UnknownAccountException("用户不存在");
}
}
else {
throw new CaptchaException("验证码异常");
}
}
/**
* 验证码校验
*
* @param token
* @return boolean
*/
protected boolean doCaptchaValidate(UsernamePasswordCaptchaToken token) {
String captcha =
(String) SecurityUtils.getSubject().getSession().getAttribute(LoginEnum.LOGIN_CAPTCHA.getKey());
logger.info(captcha);
if (captcha != null && !captcha.equalsIgnoreCase(token.getCaptchaCode())) {
throw new CaptchaException("验证码错误!");
}
return true;
}
@Autowired
public void setUserService(IUserService userService) {
this.userService = userService;
}
/**
* 用户切换岗位时清除缓存的信息
*/
@Override
public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
super.clearCachedAuthorizationInfo(principals);
}
@Override
public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
return super.getAuthorizationInfo(principals);
}
}
因为我要在controller注入realm对象(因为切换岗位时要手动设置shiro缓存的权限信息),如果是spring 多例管理的话,在调用时,每个realm的getName()是不一样的,执行getAuthorizationInfo()方法会出现问题;所以请教把当前realm配置成为单例,getName()是一样的,就可以使用controller中配置的realm调用getAuthorizationInfo()方法,手动的处理shiro的权限管理
没有代码很难猜到为什么要使用多例。
一个Realm通常作为一个公用服务,每一次调用都应该是相同的实例。
如果不是singleton,也就是说这个Realm是有状态的,题主看一下,您的Realm是不是根据不同的状态提供不同的认证服务?