package cn.chnmuseum.party.auth.realm; import cn.chnmuseum.party.auth.token.JwtToken; import cn.chnmuseum.party.auth.util.JwtTokenUtil; import cn.chnmuseum.party.model.*; import cn.chnmuseum.party.service.PermissionService; import cn.chnmuseum.party.service.RolePermissionService; import cn.chnmuseum.party.service.RoleService; import cn.chnmuseum.party.service.TUserService; import cn.chnmuseum.party.service.impl.EmployeeRoleServiceImpl; import cn.chnmuseum.party.service.impl.EmployeeServiceImpl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; 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.subject.SimplePrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.StringRedisTemplate; import javax.annotation.Resource; import java.util.*; /** * 身份校验核心类 */ public class MyShiroRealm extends AuthorizingRealm { private static final Logger LOGGER = LoggerFactory.getLogger(MyShiroRealm.class); private static final String SHIRO_JWT_TOKEN = "shiro:jwt:token:"; //用户登录次数计数 redisKey 前缀 private String SHIRO_LOGIN_COUNT = "shiro_login_count_"; //用户登录是否被锁定 一小时 redisKey 前缀 private String SHIRO_IS_LOCK = "shiro_is_lock_"; @Resource private PermissionService permissionService; @Resource private RoleService roleService; @Resource private EmployeeServiceImpl employeeService; @Resource private EmployeeRoleServiceImpl employeeRoleService; @Resource private RolePermissionService rolePermissionService; @Resource private StringRedisTemplate stringRedisTemplate; @Resource private TUserService userService; /** * 必须重写此方法,不然Shiro会报错 */ @Override public boolean supports(AuthenticationToken token) { return token instanceof JwtToken; } /** * 认证信息.(身份验证) : Authentication 是用来验证用户身份 * * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String credentials = (String) token.getCredentials(); if (credentials == null) { throw new AuthenticationException("token为空!"); } Boolean hasToken = stringRedisTemplate.hasKey(SHIRO_JWT_TOKEN + credentials); if (hasToken == null || !hasToken) { throw new AuthenticationException("用户未登录!"); } String username = JwtTokenUtil.getUsername(credentials); if (username == null) { throw new AuthenticationException("token invalid"); } LOGGER.info("MyShiroRealm doGetAuthenticationInfo().username=" + username); // 通过username从数据库中查找 // 实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法 String userId = JwtTokenUtil.getEmployeeId(credentials); TUser user = userService.getById(userId); if (user == null) { throw new AuthenticationException("User does not exist!"); } user = userService.selectByUsername(user.getUserName()); if (JwtTokenUtil.verify(credentials, username) == null) { throw new AuthenticationException("token invalid"); } return new SimpleAuthenticationInfo(new TUser(user.getId(), user.getUserName(), user.getOrgId(), user.getOrgName(), credentials), credentials, getName()); } /** * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("权限认证方法:MyShiroRealm.doGetAuthorizationInfo()"); TUser user = (TUser) principals.getPrimaryPrincipal(); Boolean hasToken = stringRedisTemplate.hasKey(SHIRO_JWT_TOKEN + user.getJwtToken()); if (hasToken == null || !hasToken) { throw new AuthenticationException("token invalid!"); } String userId = JwtTokenUtil.getEmployeeId(user.getJwtToken()); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); List<Role> list = roleService.selectRoleByUserId(userId); List<String> ridList = new ArrayList<>(); if (list != null && !list.isEmpty()) { // 根据用户ID查询角色(role),放入到Authorization里。 Map<String, Object> map = new HashMap<>(); map.put("user_id", userId); List<EmployeeRole> employeeRoleList = this.employeeRoleService.listByMap(map); for (EmployeeRole employeeRole : employeeRoleList) { ridList.add(employeeRole.getRoleId()); } List<Role> roleList = this.roleService.listByIds(ridList); Set<String> roleSet = new LinkedHashSet<>(); for (Role role : list) { roleSet.add(role.getAlias()); ridList.add(role.getId()); } info.setRoles(roleSet); } // 根据用户ID查询权限(permission)放入到Authorization里。 QueryWrapper<RolePermission> wrapper = new QueryWrapper<>(); wrapper.in("rid", ridList).select("pid"); List<Object> permissionIdList = this.rolePermissionService.listObjs(wrapper); List<Permission> permissionList = new ArrayList<>(); if (permissionIdList.size() > 0) { QueryWrapper<Permission> ew = new QueryWrapper<>(); ew.in("id", permissionIdList); permissionList = this.permissionService.list(ew); } Set<String> permissionSet = new HashSet<>(); for (Permission permission : permissionList) { permissionSet.add(permission.getUrl()); } info.setStringPermissions(permissionSet); return info; } public void clearCachedAuthenticationInfo(String token) { SimplePrincipalCollection principals = new SimplePrincipalCollection(new Employee(token), getName()); clearCachedAuthenticationInfo(principals); } @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); } private void clearAllCachedAuthorizationInfo() { getAuthorizationCache().clear(); } private void clearAllCachedAuthenticationInfo() { getAuthenticationCache().clear(); } public void clearAllCache() { clearAllCachedAuthenticationInfo(); clearAllCachedAuthorizationInfo(); } }