1、登录时调用login
/**
* 登录
*/
@GetMapping(API_PREFIX + PATH + "/login")
public ResponseEntity loginGo(HttpServletRequest request,String userName, String password) {
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotEmpty(userName)) {
queryWrapper.eq("USER_NAME", userName);
}
HttpSession session = request.getSession(true);
User user = userService.getOne(queryWrapper);
Map map = new HashMap();
if (user != null) {
try {
currentUser.login(token);
if (currentUser.isAuthenticated() == true) {
map.put("code", "1");
map.put("message", "登录成功");
map.put("userId", user.getId());
session.setAttribute("user", user);
return ResponseEntity.ok(map);
} else {
map.put("code", "0");
map.put("message", "用户名密码错误");
return ResponseEntity.ok(map);
}
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("登录失败");
}
}
map.put("code", "0");
map.put("message", "用户不存在");
return ResponseEntity.ok(map);
2、配置ShiroConfig,后面token中的密码加密用
/**
* 密码匹配凭证管理器
*
* @return
*/
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 采用MD5方式加密
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
// 设置加密次数
hashedCredentialsMatcher.setHashIterations(1024);
return hashedCredentialsMatcher;
}
3、通过上面的currentUser.login(token)方法会自动调用ShiroRealm的doGetAuthenticationInfo方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 将token装换成UsernamePasswordToken
UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
// 获取用户名即可
String username = upToken.getUsername();
// 查询数据库,是否查询到用户名和密码的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotEmpty(username)) {
queryWrapper.eq("USER_NAME", username);
}
User userInfo = userService.getOne(queryWrapper);
if(userInfo != null) {
// 如果查询到了,封装查询结果,返回给我们的调用
Object principal = userInfo;
Object credentials = userInfo.getPassword();
// 获取盐值,即用户名(用此值和token中的密码进行加密,加密结果和credentials比较,如果一致就算登录成功)
ByteSource salt = ByteSource.Util.bytes(username);
String realmName = this.getName();
// 将账户名,密码,盐值,realmName实例化到SimpleAuthenticationInfo中交给Shiro来管理
info = new SimpleAuthenticationInfo(principal, credentials, salt, realmName);
}else {
// 如果没有查询到,抛出一个异常
throw new AuthenticationException();
}
return info;
}
4、会调用抽象父类的AuthenticatingRealm的方法getAuthenticationInfo
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info = this.getCachedAuthenticationInfo(token);
if (info == null) {
info = this.doGetAuthenticationInfo(token);
log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
if (token != null && info != null) {
this.cacheAuthenticationInfoIfPossible(token, info);
}
} else {
log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
}
if (info != null) {
// 通过info中保存的realmName获取加密方法、加密次数、加密salt、加密token中的密码
// 加密完的token密码和info中保存的密码进行比较,如果相等,返回true,验证通过
this.assertCredentialsMatch(token, info);
} else {
log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token);
}
return info;
}