package com.fd.shiro; import com.fd.entity.User; import com.fd.repository.UserRepository; import lombok.extern.log4j.Log4j2; 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.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * 配置不校验的话,是不会走这个方法的 */ @Log4j2 @Service public class MyRealm extends AuthorizingRealm { @Autowired private UserRepository userRepository; @Autowired private RedisTemplate redisTemplate; /** * 大坑!,必须重写此方法,不然Shiro会报错 */ @Override public boolean supports(AuthenticationToken token) { return token instanceof JWTToken; } /** * 只有当需要检测用户权限的时候才会调用此方法,例如checkRole,checkPermission之类的 * * principals: 是token */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = JWTUtil.getUsername(principals.toString()); User user = userRepository.findByUsername(username); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.addRole(user.getRole()); // db 添加权限时,用“,”隔开 Set permission = new HashSet<>(Arrays.asList(user.getPermission().split(","))); simpleAuthorizationInfo.addStringPermissions(permission); return simpleAuthorizationInfo; } /** * 默认使用此方法进行用户名正确与否验证,错误抛出异常即可。 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { // log.warn("run doGetAuthenticationInfo"); String token = (String) auth.getCredentials(); // log.warn("token: {}", token); // 解密获得username,用于和数据库进行对比 String username = JWTUtil.getUsername(token); if (username == null) { log.info("error token username"); throw new AuthenticationException("token invalid"); } User user = userRepository.findByUsername(username); if (user == null) { log.info("error token user"); throw new AuthenticationException("User didn't existed!"); } // 校验请求token是否跟redis token一致 String redisToken = (String) redisTemplate.opsForValue().get(user.getUsername()); if (!token.equals(redisToken)) { log.info("error token redis"); throw new AuthenticationException("token invalid"); } if (! JWTUtil.verify(token, username, user.getPassword())) { log.info("error token username or password"); throw new AuthenticationException("token invalid"); } // log.warn("end doGetAuthenticationInfo"); return new SimpleAuthenticationInfo(token, token, "my_realm"); } }