2、登录验证管理
关于登录验证的一些逻辑,以及赋权等操作,我们都放在 LoginRelam.java 文件中
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.zyxx.sbm.entity.UserInfo; import com.zyxx.sbm.service.RolePermissionService; import com.zyxx.sbm.service.UserInfoService; import com.zyxx.sbm.service.UserRoleService; import org.apache.shiro.authc.*; import org.apache.shiro.authc.credential.CredentialsMatcher; 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; import java.util.Set; /** * 登录授权 */ public class LoginRelam extends AuthorizingRealm { @Autowired private UserInfoService userInfoService; @Autowired private UserRoleService userRoleService; @Autowired private RolePermissionService rolePermissionService; /** * 身份认证 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 获取基于用户名和密码的令牌:实际上这个authcToken是从LoginController里面currentUser.login(token)传过来的 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; //根据用户名查找到用户信息 QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("account", token.getUsername()); UserInfo userInfo = userInfoService.getOne(queryWrapper); // 没找到帐号 if (null == userInfo) { throw new UnknownAccountException(); } // 校验用户状态 if ("1".equals(userInfo.getStatus())) { throw new DisabledAccountException(); } // 认证缓存信息 return new SimpleAuthenticationInfo(userInfo, userInfo.getPassword(), ByteSource.Util.bytes(userInfo.getAccount()), getName()); } /** * 角色授权 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { UserInfo authorizingUser = (UserInfo) principalCollection.getPrimaryPrincipal(); if (null != authorizingUser) { //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission) SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //获得用户角色列表 Set<String> roleSigns = userRoleService.listUserRoleByUserId(authorizingUser.getId()); simpleAuthorizationInfo.addRoles(roleSigns); //获得权限列表 Set<String> permissionSigns = rolePermissionService.listRolePermissionByUserId(authorizingUser.getId()); simpleAuthorizationInfo.addStringPermissions(permissionSigns); return simpleAuthorizationInfo; } return null; } /** * 自定义加密规则 * * @param credentialsMatcher */ @Override public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) { // 自定义认证加密方式 CustomCredentialsMatcher customCredentialsMatcher = new CustomCredentialsMatcher(); // 设置自定义认证加密方式 super.setCredentialsMatcher(customCredentialsMatcher); } }
以上就是登录时,需要指明 shiro 对用户的一些验证、授权等操作,还有自定义密码验证规则,在第3步会讲到,获取角色列表,权限列表,需要获取到角色与权限的标识,每一个角色,每一个权限都有唯一的标识,装入 Set 中
3、自定义密码验证规则
密码的验证规则,我们放在了 CustomCredentialsMatcher.java 文件中
import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.SimpleCredentialsMatcher; import org.apache.shiro.crypto.hash.SimpleHash; /** * @ClassName CustomCredentialsMatcher * 自定义密码加密规则 * @Author Lizhou * @Date 2020-07-10 16:24:24 **/ public class CustomCredentialsMatcher extends SimpleCredentialsMatcher { @Override public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; //加密类型,密码,盐值,迭代次数 Object tokenCredentials = new SimpleHash("md5", token.getPassword(), token.getUsername(), 6).toHex(); // 数据库存储密码 Object accountCredentials = getCredentials(info); // 将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false return equals(tokenCredentials, accountCredentials); } }
我们采用的密码加密方式为 MD5 加密,加密 6 次,使用登录账户作为加密密码的盐进行加密
4、密码加密工具
上面我们自定义了密码加密规则,我们创建一个密码加密的工具类 PasswordUtils.java 文件
import org.apache.shiro.crypto.hash.Md5Hash; /** * 密码加密的处理工具类 */ public class PasswordUtils { /** * 迭代次数 */ private static final int ITERATIONS = 6; private PasswordUtils() { throw new AssertionError(); } /** * 字符串加密函数MD5实现 * * @param password 密码 * @param loginName 用户名 * @return */ public static String getPassword(String password, String loginName) { return new Md5Hash(password, loginName, ITERATIONS).toString(); } }