This commit is contained in:
2023-05-19 17:38:09 +08:00
parent e41797c750
commit 3dc6fb7828
77 changed files with 1000 additions and 256 deletions

View File

@ -8,6 +8,7 @@ import com.qiaoba.auth.handler.AccessDeniedHandler;
import com.qiaoba.auth.handler.LogoutHandler;
import com.qiaoba.auth.properties.AuthConfigProperties;
import com.qiaoba.auth.utils.TokenUtil;
import com.qiaoba.common.base.constants.BaseConstant;
import com.qiaoba.common.redis.service.RedisService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -21,6 +22,7 @@ import org.springframework.security.config.annotation.web.configurers.Expression
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import javax.annotation.PostConstruct;
@ -40,9 +42,9 @@ public class SpringSecurityConfig {
private final AuthConfigProperties authConfigProperties;
private final AccessDeniedHandler accessDeniedHandler;
private final LogoutHandler logoutHandler;
private final JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
private final RedisService redisService;
private final LogoutHandler logoutHandler;
/**
* 创建Token秘钥
@ -65,7 +67,8 @@ public class SpringSecurityConfig {
for (String url : authConfigProperties.getWhitelist()) {
registry.antMatchers(url).permitAll();
}
// 文件资源 无需鉴权
registry.antMatchers(BaseConstant.RESOURCE_PREFIX + "/**").permitAll();
// 由于使用的是JWT我们这里不需要csrf
httpSecurity.csrf()
.disable()
@ -90,7 +93,7 @@ public class SpringSecurityConfig {
httpSecurity.logout().logoutUrl(SecurityConstant.LOGOUT_URL).logoutSuccessHandler(logoutHandler);
// 添加JWT filter
httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter, LogoutFilter.class);
return httpSecurity.build();
}
}

View File

@ -26,6 +26,7 @@ public class SecurityConstant {
public static final String REGISTER_ON_OFF_KEY = "sys_config:sys.account.registerUser";
public static final String REGISTER_ON = "true";
public static final String REDIS_SECRET_KEY = "sys:secret:secret";
public static final String USER_DETAILS_REDIS_KEY = "user_details:";
/**
* 登录成功
*/
@ -54,7 +55,7 @@ public class SecurityConstant {
* Xss过滤白名单
*/
public final static List<String> XSS_WHITELIST = Arrays.asList(
"/captchaImage" ,
"/captchaImage",
"/login",
"/workflow/process/start",
"/workflow/model/save"
@ -64,8 +65,8 @@ public class SecurityConstant {
* 需要限流的接口
*/
public final static List<String> LIMIT_URI = Arrays.asList(
"/captchaImage" ,
"/login" ,
"/captchaImage",
"/login",
"/register"
);
@ -78,4 +79,5 @@ public class SecurityConstant {
* 同IP每秒最大允许访问次数
*/
public final static Integer MAX_RATE_LIMIT_TOTAL = 5;
}

View File

@ -46,7 +46,7 @@ public class LoginUser implements UserDetails {
/**
* 角色列表
*/
private List<String> roleIds;
private List<String> roleKeys;
/**
@ -58,13 +58,13 @@ public class LoginUser implements UserDetails {
public LoginUser() {
}
public LoginUser(String userId, String deptId, String username, String nickname, List<String> roleIds, Set<String> permissions) {
public LoginUser(String userId, String deptId, String username, String nickname, List<String> roleKeys, Set<String> permissions) {
this.userId = userId;
this.deptId = deptId;
this.username = username;
this.permissions = permissions;
this.nickname = nickname;
this.roleIds = roleIds;
this.roleKeys = roleKeys;
}
public String getUserId() {
@ -84,12 +84,12 @@ public class LoginUser implements UserDetails {
}
public List<String> getRoleIds() {
return roleIds;
public List<String> getRoleKeys() {
return roleKeys;
}
public void setRoleIds(List<String> roleIds) {
this.roleIds = roleIds;
public void setRoleKeys(List<String> roleKeys) {
this.roleKeys = roleKeys;
}
public Set<String> getPermissions() {

View File

@ -0,0 +1,55 @@
package com.qiaoba.auth.entity;
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;
/**
* 部门ID
*/
private String deptId;
/**
* 登录账号
*/
private String username;
/**
* 用户名称
*/
private String nickname;
/**
* 角色列表
*/
private List<String> roleKeys;
/**
* 权限列表
*/
private Set<String> permissions;
}

View File

@ -2,7 +2,6 @@ package com.qiaoba.auth.filters;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.auth.constants.SecurityConstant;
import com.qiaoba.auth.properties.AuthConfigProperties;
import com.qiaoba.auth.utils.TokenUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -17,7 +16,6 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
/**
* JwtAuthenticationTokenFilter
@ -31,25 +29,20 @@ import java.util.Objects;
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private final UserDetailsService userDetailsService;
private final AuthConfigProperties authConfigProperties;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
// 鉴权白名单, 放行
if (authConfigProperties.getWhitelist().contains(request.getRequestURI())) {
chain.doFilter(request, response);
return;
}
// 取Header中的Token
String authHeader = request.getHeader(SecurityConstant.TOKEN_HEADER);
if (StrUtil.isNotBlank(authHeader) && authHeader.startsWith(SecurityConstant.TOKEN_HEAD)) {
String authToken = authHeader.substring(SecurityConstant.TOKEN_HEAD.length());
if (TokenUtil.validateToken(authToken)) {
String username = TokenUtil.getUserNameFromToken(authToken);
if (StrUtil.isNotBlank(username) && Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);

View File

@ -1,12 +1,16 @@
package com.qiaoba.auth.handler;
import com.qiaoba.auth.entity.LoginUser;
import com.qiaoba.common.redis.service.RedisService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 退出处理器
@ -16,11 +20,15 @@ import javax.servlet.http.HttpServletResponse;
* @since 2022/1/4 0004 下午 16:20
*/
@Component
@RequiredArgsConstructor
public class LogoutHandler implements LogoutSuccessHandler {
private final RedisService redisService;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) {
//删除SecurityContext上下文中的信息
SecurityContextHolder.clearContext();
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// 删除缓存中的用户信息
LoginUser user = (LoginUser) authentication.getPrincipal();
redisService.del(user.getUserId());
}
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.HashMap;
import java.util.Map;
@ -23,7 +24,6 @@ public class TokenUtil {
*/
public static String secret;
public static String generateToken(String username) {
DateTime now = DateTime.now();
// 3天过期
@ -38,7 +38,6 @@ public class TokenUtil {
payload.put(JWTPayload.NOT_BEFORE, now);
//载荷
payload.put(JWTPayload.SUBJECT, username);
return JWTUtil.createToken(payload, secret.getBytes());
}