предисловие
Spring Boot интегрирует Shiro для необходимой предварительной работы, такой как аутентификация личности.Вы можете искать в Интернете.Эта статья в основном посвящена пользовательской аутентификации шифрования для аутентификации пользователя при входе в систему, и Shiro сохраняет содержимое пользователей, вошедших в систему, для последующего использования.
1.1 Вход по электронной почте пользователя
Примечание. Когда пользователь настраивает адрес для входа в Широ, фактическая реализация URL-адреса запроса логики проверки входа должна быть установлена на отсутствие проверки (новичок).
ShiroConfig.java
/**
* Shiro Filter
*
* @param securityManager securityManager
* @return shiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
log.info("======== Shiro config ==========");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// jwt过滤器
Map<String, Filter> filterMap = shiroFilterFactoryBean.getFilters();
filterMap.put("jwt", new JWTFilter());
shiroFilterFactoryBean.setFilters(filterMap);
shiroFilterFactoryBean.setUnauthorizedUrl("/401");
// 设置登录路径
shiroFilterFactoryBean.setLoginUrl("/login");
// 拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 实际登录地址,不能为/login
filterChainDefinitionMap.put("/doLogin", "anon");
filterChainDefinitionMap.put("/login", "anon");
......
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
Электронная почта пользователя для входа: электронная почта в качестве учетной записи;
LoginController.java
/**
* login
*
* @param email 登录邮箱
* @param password 登录密码
* @return login
*/
@PostMapping("/doLogin")
public String login(String email, String password) {
// 创建Subject实例
Subject subject = SecurityUtils.getSubject();
// 封装用户数据
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(email, password);
// 登录判断
try {
subject.login(usernamePasswordToken);
if (subject.isAuthenticated()) {
return "redirect:/customers";
}
} catch (UnknownAccountException e) {
log.info("---> {}登录失败", email);
}
return "login";
}
1.2 Пароль пользователя плюс проверка соли
Примечание. Shiro сама поддерживает проверку шифрования MD5, используйте HashedCredentialsMatcher для настройки правил шифрования для шифрования.
/**
* 这里需要设置成与PasswordEncrypter类相同的加密规则
*
* 在doGetAuthenticationInfo认证登陆返回SimpleAuthenticationInfo时会使用hashedCredentialsMatcher
* 把用户填入密码加密后生成散列码与数据库对应的散列码进行对比
*
* HashedCredentialsMatcher会自动根据AuthenticationInfo的类型是否是SaltedAuthenticationInfo来获取credentialsSalt盐
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 散列算法, 与注册时使用的散列算法相同
hashedCredentialsMatcher.setHashIterations(2);// 散列次数, 与注册时使用的散列册数相同
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);// 生成16进制, 与注册时的生成格式相同
return hashedCredentialsMatcher;
}
Однако он не использует собственный метод шифрования для зашифрованного пользователем хранилища, поэтому необходимо переписать метод setCredentialsMatcher в Realm, чтобы обеспечить единство (кастомизацию) шифрования и проверки.Я выбираю переписать метод вместо пользовательского шифрования , Класс проверки. (Проверьте код класса Realm ниже)
AuthRealmForWeb.java
/**
* 校验用户身份
*
* @param auth
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
String email = (String) auth.getPrincipal();
Optional<User> userOptional = userService.findByEmail(email);
if (!userOptional.isPresent()) {
throw new UnknownAccountException("未查询到该用户信息");
}
User user = userOptional.get();
// 此处第一个参数传递user,则将登录user信息存储备用
// 如果使用加盐验证,则第三个参数必须使用ByteSource.Util.bytes(xxx)
SimpleAuthenticationInfo authenticationInfo =
new SimpleAuthenticationInfo(user, user.getPassword(),
ByteSource.Util.bytes(user.getSalt()), getName());
return authenticationInfo;
}
/**
* Authorizaton 授权
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 赋予登录用户权限
Optional<List<Role>> optionalRoleList = userRoleService.findRolesByUserId(user.getId());
if (optionalRoleList.isPresent()) {
// 授权
for (Role role : optionalRoleList.get()) {
authorizationInfo.addRole(role.getName());
Optional<List<Permission>> optionalPermissions = rolePermissionService.findPermissionsByRoleIds(
Arrays.asList(role.getId()));
if (optionalPermissions.isPresent()) {
authorizationInfo.addStringPermissions(optionalPermissions.get()
.stream().map(Permission::getPval).collect(Collectors.toList()));
}
}
}
return authorizationInfo;
}
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
credentialsMatcher = (token, info) -> {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
// 验证时传递的加密盐
String salt = new String(((SimpleAuthenticationInfo) info).getCredentialsSalt().getBytes());
// 登录录入的密码
String password = new String(usernamePasswordToken.getPassword());
// 自定义的加盐加密方式
String realPassword = Hashing.sha512().hashString(password + salt,
Charsets.UTF_8).toString().substring(0, 17);
return realPassword.equalsIgnoreCase(info.getCredentials().toString());
};
super.setCredentialsMatcher(credentialsMatcher);
}
1.3 Хранить информацию о пользователе
Сохраните информацию о пользователе, как показано в предыдущем разделе 1.2, просто установите первый параметр для текущего пользователя:
// 此处第一个参数传递user,则将登录user信息存储备用
// 如果使用加盐验证,则第三个参数必须使用ByteSource.Util.bytes(xxx)
SimpleAuthenticationInfo authenticationInfo =
new SimpleAuthenticationInfo(user, user.getPassword(),
ByteSource.Util.bytes(user.getSalt()), getName());
После сохранения информации о пользователе, как получить сохраненную информацию о пользователе? Очень просто, он хранится в Теме следующим образом:
User currentUser = (User) SecurityUtils.getSubject().getPrincipal();
Суммировать
Shrio слышал о нем, но сам не пользовался, а просто использовал в проекте, чтобы сделать сюрприз.Обнаружил, что статьи в интернете не подходят для моих нужд, а соответствующего кода нет; эта статья сочетается с реальными потребностями моего собственного проекта, записываю ее и имею возможность обновить ее позже, связанную с Сиро, для углубления понимания;
Если у вас есть какие-либо вопросы или сомнения в тексте, пожалуйста, поправьте меня!