跳至主要內容

shiro

chanchaw大约 2 分钟languagejava

案例

获取当前登录用户

获取用户表主键字段的值,在旭纸业项目中获取的字段是 sys_user.id

SecurityUtils.getSubject().getPrincipal()

自定义多认证条件

2022年1月14日 14:19:19 旭纸业项目要求在登录账号外再增加一个手机号作为第二账号进行登录

  1. 创建带有附加属性的继承 shiro 类 UsernamePasswordToken 的自定义类,用于保存多出来的认证条件
package com.xdf.xzymanagementsystem.config;

import org.apache.shiro.authc.UsernamePasswordToken;

public class MyUsernamePasswordToken extends UsernamePasswordToken {
    private String userPhone;

    public String getUserPhone() {
        return userPhone;
    }

    public void setUserPhone(String userPhone) {
        this.userPhone = userPhone;
    }

    public MyUsernamePasswordToken() {
    }

    public MyUsernamePasswordToken(String username,String password,String userPhone) {
        super(username,password);
        this.userPhone = userPhone;
    }

    @Override
    public String toString() {
        return "MyUsernamePasswordToken{" +
                "userPhone='" + userPhone + '\'' +
                '}';
    }
}

  1. 项目中继承 shiro 类 AuthorizingRealm 的自定义类 ShiroRealm 中有两个方法需要修改,第一个是用于鉴定请求 token 的引用类型的 support - 后面的 MyUsernamePasswordToken 是自定义类
@Override
public boolean supports(AuthenticationToken token) {
    return token !=null && token instanceof MyUsernamePasswordToken;
}
  1. 修改认证方法 doGetAuthenticationInfo,注意还有个同名的方法,但是参数类型不一样,是用来做鉴权的,不要修改错了 shiro01

  2. 最后修改登录请求的 controller 将接受的 SysUser 类型的参数构建为自定义的对象,交给 shiro 进行登录

@PostMapping("/login")
@ResponseBody
public ResponseResult<Void> login(SysUser user) throws Exception {
    if (user == null) throw new UserLoginErrorException("账号密码不能为空!");
    String loginName = user.getLoginName();
    String password = MD5Util.toMD5(user.getLoginPassword());
    //        UsernamePasswordToken token = new UsernamePasswordToken(loginName, password);
    MyUsernamePasswordToken token = new MyUsernamePasswordToken(loginName, password,user.getUserPhone());
    Subject subject = SecurityUtils.getSubject();
    try {
        subject.login(token);
    } catch (IncorrectCredentialsException e) {
        return ResponseResult.<Void>builder().success(false).message("密码错误!").build();
    } catch (Exception e) {
        return ResponseResult.<Void>builder().success(false).message(e.getMessage()).build();
    }
    Session session = subject.getSession();
    session.touch();
    return ResponseResult.<Void>builder().success(true).message(ResponseEnum.OK.getName()).build();
}

在线刷新权限缓存

原理是清理掉内存中的权限缓存数据,用户在此之后有操作则会自动重新初始化权限缓存,即应用新的权限配置 下面方法的传入参数 principal 是登录账号的主键,本功能初次用在旭纸业系统中,此处的传入参数对应该系统的 sys_user.id即用户表的主键。功能做在 com.xdf.xzymanagementsystem.util.ShiroUtils

/**
* 刷新指定用户的权限缓存
* @param principal 用户主键
*/
public static void reloadAuthorizing(Object principal) {
    RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
ShiroRealm myShiroRealm = (ShiroRealm) rsm.getRealms().iterator().next();

Subject subject = SecurityUtils.getSubject();
String realmName = subject.getPrincipals().getRealmNames().iterator().next();
SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, realmName);
subject.runAs(principals);
if(myShiroRealm.isAuthenticationCachingEnabled()) {
    myShiroRealm.getAuthenticationCache().remove(principals);
}
if(myShiroRealm.isAuthorizationCachingEnabled()) {
    // 删除指定用户shiro权限
    myShiroRealm.getAuthorizationCache().remove(principals);
}
// 刷新权限
subject.releaseRunAs();
}