This commit is contained in:
2023-07-05 17:54:53 +08:00
parent 29bd2eae48
commit 7e10a7877f
65 changed files with 867 additions and 85 deletions

View File

@ -1,28 +0,0 @@
package com.qiaoba.auth.annotation;
import java.lang.annotation.*;
/**
* 数据权限过滤注解
*
* @author ruoyi
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {
/**
* 部门表的别名
*/
public String deptAlias() default "";
/**
* 用户表的别名
*/
public String userAlias() default "";
/**
* 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取多个权限用逗号分隔开来
*/
public String permission() default "";
}

View File

@ -2,10 +2,10 @@ package com.qiaoba.auth.aspectj;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.auth.annotation.DataScope;
import com.qiaoba.auth.entity.LoginUser;
import com.qiaoba.auth.entity.dto.RoleDto;
import com.qiaoba.auth.utils.SecurityUtil;
import com.qiaoba.api.auth.annotation.DataScope;
import com.qiaoba.api.auth.entity.LoginUser;
import com.qiaoba.api.auth.entity.dto.RoleDto;
import com.qiaoba.api.auth.utils.SecurityUtil;
import com.qiaoba.common.base.entity.DataScopeParam;
import com.qiaoba.common.base.utils.DatabaseUtil;
import org.aspectj.lang.JoinPoint;

View File

@ -1,6 +1,6 @@
package com.qiaoba.auth.config;
import com.qiaoba.auth.constants.SecurityConstant;
import com.qiaoba.api.auth.constants.SecurityConstant;
import com.qiaoba.auth.filters.AuthenticationCoreFilter;
import com.qiaoba.auth.handler.AccessDeniedHandler;
import com.qiaoba.auth.handler.LogoutHandler;

View File

@ -1,43 +0,0 @@
package com.qiaoba.auth.constants;
/**
* 安全常量
*
* @author ailanyin
* @version 1.0
* @since 2022/9/8 0008 下午 14:54
*/
public class SecurityConstant {
public static final String LOGOUT_URI = "/logout";
public static final String HAS_BEEN_PULLED_BLACK = "你的IP已经被系统拉黑, 请联系管理员处理";
public static final String ACCESS_DENIED = "暂无权限访问, 请重新登录";
public static final String BLACKLIST_KEY = "login:blacklist:";
public static final String LOGIN_ERROR_COUNT = "login:errorCount:";
public static final String BLACKLIST_ON = "true";
public static final String CAPTCHA_KEY = "login:captcha:";
public static final String REDIS_SECRET_KEY = "sys:secret:secret";
public static final String USER_DETAILS_REDIS_KEY = "user_details:";
public static final String ONLINE_USER_REDIS_KEY = "online_user:";
public static final String LOGGED_USER_REDIS_KEY = "logged_user:";
/**
* 密码错误
*/
public static final String PASSWORD_ERROR = "密码错误";
/**
* token header
*/
public static final String TOKEN_HEADER = "Authorization";
/**
* token前缀
*/
public static final String TOKEN_HEAD = "Bearer ";
}

View File

@ -1,196 +0,0 @@
package com.qiaoba.auth.entity;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.qiaoba.auth.entity.dto.RoleDto;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 登录用户身份权限
*
* @author ailanyin
* @version 1.0
* @since 2021/10/15 0015 上午 10:05
*/
public class LoginUser implements UserDetails {
private static final long serialVersionUID = 1L;
/**
* 设备号 暂用UUID
*/
private String deviceSn;
/**
* 用户ID
*/
private String userId;
/**
* 部门ID
*/
private String deptId;
/**
* 登录账号
*/
private String username;
/**
* 用户名称
*/
private String nickname;
/**
* 角色列表
*/
private List<String> roleKeys;
/**
* 权限列表
*/
private Set<String> permissions;
private List<RoleDto> roles;
public LoginUser() {
}
public LoginUser(String deviceSn, String userId, String deptId, String username, String nickname, List<RoleDto> roles, List<String> roleKeys, Set<String> permissions) {
this.deviceSn = deviceSn;
this.userId = userId;
this.deptId = deptId;
this.username = username;
this.permissions = permissions;
this.nickname = nickname;
this.roleKeys = roleKeys;
this.roles = roles;
}
public String getDeviceSn() {
return deviceSn;
}
public void setDeviceSn(String deviceSn) {
this.deviceSn = deviceSn;
}
public List<RoleDto> getRoles() {
return roles;
}
public void setRoles(List<RoleDto> roles) {
this.roles = roles;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public List<String> getRoleKeys() {
return roleKeys;
}
public void setRoleKeys(List<String> roleKeys) {
this.roleKeys = roleKeys;
}
public Set<String> getPermissions() {
return permissions;
}
public void setPermissions(Set<String> permissions) {
this.permissions = permissions;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public String getPassword() {
return null;
}
/**
* 账户是否未过期,过期无法验证
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 指定用户是否解锁,锁定的用户无法进行身份验证
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
*
* @return boolean
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 是否可用 ,禁用的用户不能身份验证
*
* @return boolean
*/
@Override
public boolean isEnabled() {
return true;
}
@Override
@JsonIgnore
public Collection<? extends GrantedAuthority> getAuthorities() {
//返回当前用户的权限
return permissions.stream()
.filter(StrUtil::isNotBlank)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
}

View File

@ -1,63 +0,0 @@
package com.qiaoba.auth.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 在线用户
*
* @author ailanyin
* @version 1.0
* @since 2023/5/25 17:05
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OnlineUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 设备号 暂用UUID
*/
private String deviceSn;
/**
* 登录账号
*/
private String username;
/**
* 用户名称
*/
private String nickname;
/**
* 登录IP地址
*/
private String ip;
/**
* 登录地点
*/
private String address;
/**
* 浏览器类型
*/
private String browser;
/**
* 操作系统
*/
private String os;
/**
* 登录时间
*/
private Date loginTime;
}

View File

@ -1,65 +0,0 @@
package com.qiaoba.auth.entity;
import com.qiaoba.auth.entity.dto.RoleDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
/**
* @author ailanyin
* @version 1.0
* @since 2023/5/19 16:55
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SecurityUser implements Serializable {
/**
* 用户ID
*/
private String userId;
/**
* 设备SN
*/
private String deviceSn;
/**
* 部门ID
*/
private String deptId;
/**
* 登录账号
*/
private String username;
/**
* 用户名称
*/
private String nickname;
/**
* 角色列表
*/
private List<RoleDto> roles;
/**
* 角色Key列表
*/
private List<String> roleKeys;
/**
* 权限列表
*/
private Set<String> permissions;
}

View File

@ -1,33 +0,0 @@
package com.qiaoba.auth.entity.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 在线用户
*
* @author ailanyin
* @version 1.0
* @since 2023/5/22 17:08
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OnlineUserDto implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 登录账号
*/
private String username;
/**
* 设备号 暂用UUID
*/
private String deviceSn;
}

View File

@ -1,23 +0,0 @@
package com.qiaoba.auth.entity.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 角色
*
* @author ailanyin
* @version 1.0
* @since 2023/5/22 17:08
*/
@Data
public class RoleDto implements Serializable {
private static final long serialVersionUID = 1L;
private String roleId;
private String roleKey;
private String roleName;
private String dataScope;
}

View File

@ -1,11 +1,11 @@
package com.qiaoba.auth.filters;
import com.qiaoba.api.auth.service.AuthConfigApiService;
import com.qiaoba.auth.constants.SecurityConstant;
import com.qiaoba.auth.entity.dto.OnlineUserDto;
import com.qiaoba.api.auth.constants.SecurityConstant;
import com.qiaoba.api.auth.entity.dto.OnlineUserDto;
import com.qiaoba.auth.properties.AuthConfigProperties;
import com.qiaoba.auth.service.OnlineUserService;
import com.qiaoba.auth.utils.TokenUtil;
import com.qiaoba.api.auth.service.OnlineUserService;
import com.qiaoba.api.auth.utils.TokenUtil;
import com.qiaoba.common.redis.service.RedisService;
import com.qiaoba.common.web.utils.ResponseUtil;
import com.qiaoba.common.web.utils.UriUtil;

View File

@ -1,7 +1,7 @@
package com.qiaoba.auth.handler;
import cn.hutool.http.HttpStatus;
import com.qiaoba.auth.constants.SecurityConstant;
import com.qiaoba.api.auth.constants.SecurityConstant;
import com.qiaoba.common.web.utils.ResponseUtil;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

View File

@ -1,7 +1,7 @@
package com.qiaoba.auth.handler;
import com.qiaoba.auth.entity.LoginUser;
import com.qiaoba.auth.service.OnlineUserService;
import com.qiaoba.api.auth.entity.LoginUser;
import com.qiaoba.api.auth.service.OnlineUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

View File

@ -1,75 +0,0 @@
package com.qiaoba.auth.service;
import com.qiaoba.auth.entity.OnlineUser;
import com.qiaoba.common.base.entity.BasePage;
import java.util.List;
/**
* 在线用户 服务层
*
* @author ailanyin
* @version 1.0
* @since 2023/5/25 17:15
*/
public interface OnlineUserService {
/**
* 新增
*
* @param onlineUser onlineUser
*/
void insert(OnlineUser onlineUser);
/**
* 删除(强退)
*
* @param username 登录账号
* @param deviceSn 设备号
* @param deleteOwn 是否是删除自己
*/
void deleteOne(String username, String deviceSn, Boolean deleteOwn);
/**
* 删除(强退)
*
* @param username 登录账号
*/
void deleteAll(String username);
/**
* 查询
*
* @param username 登录账号
* @param deviceSn deviceSn
* @return 在线用户
*/
OnlineUser selectOne(String username, String deviceSn);
/**
* 批量查询
*
* @param username username
* @return list
*/
List<OnlineUser> selectList(String username);
/**
* 检查设备是否是最新登陆的设备
*
* @param username username
* @param deviceSn deviceSn
* @return 结果
*/
Boolean checkIsLastLogged(String username, String deviceSn);
/**
* 分页查询列表
*
* @param pageNum pageNum
* @param pageSize pageSize
* @param username username
* @return list
*/
BasePage selectPageList(Integer pageNum, Integer pageSize, String username);
}

View File

@ -2,7 +2,7 @@ package com.qiaoba.auth.service.impl;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.api.auth.service.AuthConfigApiService;
import com.qiaoba.auth.constants.SecurityConstant;
import com.qiaoba.api.auth.constants.SecurityConstant;
import com.qiaoba.common.base.constants.ConfigConstant;
import com.qiaoba.common.base.exceptions.ServiceException;
import com.qiaoba.common.redis.service.RedisService;

View File

@ -3,11 +3,11 @@ package com.qiaoba.auth.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.api.auth.service.SysUserDetailsApiService;
import com.qiaoba.auth.constants.SecurityConstant;
import com.qiaoba.auth.entity.OnlineUser;
import com.qiaoba.auth.entity.dto.OnlineUserDto;
import com.qiaoba.auth.service.OnlineUserService;
import com.qiaoba.auth.utils.TokenUtil;
import com.qiaoba.api.auth.constants.SecurityConstant;
import com.qiaoba.api.auth.entity.OnlineUser;
import com.qiaoba.api.auth.entity.dto.OnlineUserDto;
import com.qiaoba.api.auth.service.OnlineUserService;
import com.qiaoba.api.auth.utils.TokenUtil;
import com.qiaoba.common.base.constants.BaseConstant;
import com.qiaoba.common.base.entity.BasePage;
import com.qiaoba.common.base.exceptions.ServiceException;

View File

@ -1,74 +0,0 @@
package com.qiaoba.auth.utils;
import com.qiaoba.auth.entity.LoginUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* SecurityUtil
*
* @author ailanyin
* @version 1.0
* @since 2022/8/16 0016 下午 14:51
*/
public class SecurityUtil {
private static final BCryptPasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
/**
* 获取登录用户的账号
*
* @return username
*/
public static String getLoginUsername() {
return getLoginUser().getUsername();
}
/**
* 获取登录用户的账号
*
* @return nickname
*/
public static String getLoginNickname() {
return getLoginUser().getNickname();
}
/**
* 获取登录用户的ID
*
* @return userId
*/
public static String getLoginUserId() {
return getLoginUser().getUserId();
}
public static LoginUser getLoginUser() {
SecurityContext ctx = SecurityContextHolder.getContext();
Authentication auth = ctx.getAuthentication();
return (LoginUser) auth.getPrincipal();
}
/**
* 加密密码
*
* @param password 原密码
* @return 加密后密码
*/
public static String encryptPassword(String password) {
return PASSWORD_ENCODER.encode(password);
}
/**
* 判断密码是否相同
*
* @param rawPassword 真实密码
* @param encodedPassword 加密后字符
* @return 结果
*/
public static boolean matchesPassword(String rawPassword, String encodedPassword) {
return PASSWORD_ENCODER.matches(rawPassword, encodedPassword);
}
}

View File

@ -1,54 +0,0 @@
package com.qiaoba.auth.utils;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.auth.constants.SecurityConstant;
import com.qiaoba.auth.entity.dto.OnlineUserDto;
import com.qiaoba.common.base.constants.BaseConstant;
import com.qiaoba.common.base.exceptions.ServiceException;
import javax.servlet.http.HttpServletRequest;
/**
* TokenUtil
*
* @author ailanyin
* @version 1.0
* @since 2022/6/8 0008 上午 11:44
*/
public class TokenUtil {
/**
* jwt 加解密密钥,第一次项目启动时创建随机数
*/
public static String secret;
public static Integer expireTime = 72;
private static final String TOKEN_TEMPLATE = "{}:{}";
public static String generateToken(String username, String deviceSn) {
return StrUtil.format(TOKEN_TEMPLATE, username, deviceSn);
}
public static String getToken(HttpServletRequest request, boolean allowNull) {
// 取Header中的Token
String authHeader = request.getHeader(SecurityConstant.TOKEN_HEADER);
if (StrUtil.isNotBlank(authHeader) && authHeader.startsWith(SecurityConstant.TOKEN_HEAD)) {
return authHeader.substring(SecurityConstant.TOKEN_HEAD.length());
}
if (allowNull) {
return null;
}
throw new ServiceException("Token不存在");
}
public static OnlineUserDto getUsernameAndDeviceSn(String token) {
try {
String[] split = token.split(BaseConstant.COLON_JOIN_STR);
return new OnlineUserDto(split[0], split[1]);
} catch (Exception e) {
throw new ServiceException("Token解析失败");
}
}
}