java
复制代码
package com.system.security;
import com.system.common.utlis.jwt.JwtUtils;
import com.system.common.utlis.result.Prefix;
import com.system.common.utlis.result.ResData;
import com.system.common.utlis.result.ResEnum;
import com.system.system.dao.RoleDao;
import com.system.system.entity.vo.AuthVO;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author kuaiting
*/
@Configuration
public class SecurityConfig {
@Resource
JwtUtils jwtUtils;
@Resource
private JwtFilter jwtFilter;
@Resource
private RoleDao roleDao;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
private final String[] paths = {
"/druid/**", "/system/captcha/line",
"/druid/login.html/**",
"/system/login", "/js/**", "/*/*.json", "/*/*.yml",
"/prims/**", "/type/**", "/system/file/**",
"/diagram-viewer/**", "/images/**",
"/api/login/**", "/api/file/**",
"/css/**", "/*/*.ico", "/swagger-resources/**",
"/swagger/**", "/swagger-ui/**",
"/webjars/**", "/v3/**", "/v2/**", "/doc.html/**"
};
@Bean
public SecurityFilterChain securityChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests(conf -> conf.requestMatchers(paths).permitAll()
.anyRequest().authenticated())
.formLogin(conf ->
conf.loginProcessingUrl("/system/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(this::onAuthenticationSuccess)
.failureHandler(this::onAuthenticationFailure))
.exceptionHandling(conf ->
conf.authenticationEntryPoint(this::noLogin)
.accessDeniedHandler(this::noPermission))
.logout(conf ->
conf.logoutUrl("/system/logout")
.logoutSuccessHandler(this::onLogoutSuccess))
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(conf -> conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
private void noPermission(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException e) throws IOException {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
PrintWriter writer = response.getWriter();
jsonWriter(writer, ResEnum.FORBIDDEN.getCode(), ResEnum.FORBIDDEN.getMsg());
}
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
SecurityUser user = (SecurityUser) authentication.getPrincipal();
Long uid = user.getId();
Set<String> permissions = new HashSet<>();
for (GrantedAuthority authority : user.getAuthorities()) {
String auth = authority.getAuthority();
permissions.add(auth);
}
String token = jwtUtils.createToken(user, uid, user.getUsername(),user.getPassword());
AuthVO authVo = new AuthVO();
authVo.setRole(roleDao.getUserRoles(uid));
authVo.setPermission(permissions);
authVo.setKey(Prefix.TOKEN_KEY);
authVo.setToken(token);
authVo.setExpire(jwtUtils.expireTime().getTime());
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter writer = response.getWriter();
jsonWriter(writer, ResEnum.SUCCESS.getCode(), ResEnum.SUCCESS.getMsg(), authVo);
}
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception) throws IOException {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter writer = response.getWriter();
jsonWriter(writer, ResEnum.UNAUTHORIZED.getCode(), exception.getMessage());
}
public void noLogin(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter writer = response.getWriter();
jsonWriter(writer, ResEnum.UNAUTHORIZED.getCode(), ResEnum.UNAUTHORIZED.getMsg());
}
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
String authorization = request.getHeader("Authorization");
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter writer = response.getWriter();
// 登出时,删除redis中的token
if (jwtUtils.invalidateToken(authorization)) {
jsonWriter(writer, ResEnum.SUCCESS.getCode(), ResEnum.SUCCESS.getMsg());
} else {
jsonWriter(writer, ResEnum.FAIL.getCode(), ResEnum.FAIL.getMsg());
}
}
private void jsonWriter(PrintWriter writer, Integer code, String message) {
jsonWriter(writer, code, message, null);
}
private void jsonWriter(PrintWriter writer, Integer code, String message, Object data) {
writer.write(ResData.asJson(code, message, data));
writer.flush();
writer.close();
}
private List<Long> getRoleIds(Long uid) {
return roleDao.getRoleIds(uid);
}
private List<String> getUserRoles(Long uid) {
return roleDao.getUserRoles(uid);
}
private Set<String> getPermissions(List<Long> roleIds) {
Set<String> all = new HashSet<>();
for (Long id : roleIds) {
List<String> permissions = getUserPermissions(id);
all.addAll(permissions);
}
return all;
}
private List<String> getUserPermissions(Long rid) {
return roleDao.getPermissions(rid);
}
}
java
复制代码
package com.system.common.utlis.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.system.common.utlis.redis.RedisService;
import com.system.common.utlis.result.Prefix;
import com.system.security.SecurityUser;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
@Component
public class JwtUtils {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expire}")
private Integer expire;
@Resource
private RedisService redisService;
public Boolean invalidateToken(String haeadToken) {
String token = convertToken(haeadToken);
if (token == null) {
return false;
}
try {
DecodedJWT jwt = JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
return deleteToken(jwt.getId(), jwt.getExpiresAt());
} catch (JWTVerificationException e) {
return null;
}
}
// 删除redis 中的Token
private Boolean deleteToken(String id, Date date) {
if (isInvalidToken(id)) {
return false;
}
Date now = new Date();
long expire = Math.max(date.getTime() - now.getTime(), 0);
redisService.set(Prefix.JWT_BLACK_LIST + id, id, expire);
return true;
}
// 验证 redis 中 token 是否存在
private Boolean isInvalidToken(String id) {
return Boolean.TRUE.equals(redisService.hasKey(Prefix.JWT_BLACK_LIST + id));
}
public String createToken(UserDetails details, Long id, String username,String password) {
Algorithm algorithm = Algorithm.HMAC256(secret);
redisService.set(Prefix.JWT_BLACK_LIST + id, id, expire);
return JWT.create().withJWTId(String.valueOf(id))
.withClaim("id", id)
.withClaim("username", username)
.withClaim("password", password)
.withClaim("authorities", getAuths(details))
.withExpiresAt(expireTime())
.sign(algorithm);
}
public String getAuths(UserDetails details) {
return details.getAuthorities().stream().map(GrantedAuthority::getAuthority).
collect(Collectors.joining(","));
}
// 获取过期时间
public Date expireTime() {
// 过期时间
Calendar instance = Calendar.getInstance();
instance.add(Calendar.HOUR, expire * 24); // 默认7天
return instance.getTime();
}
// 解析 JWT token
public DecodedJWT resolveToken(String haeadToken) {
String token = convertToken(haeadToken);
if (token == null) {
return null;
}
try {
DecodedJWT jwt = JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
if (isInvalidToken(jwt.getId())) {
return null;
}
Date expires = jwt.getExpiresAt();
return new Date().after(expires) ? null : jwt;
} catch (JWTVerificationException e) {
return null;
}
}
// 解析 截取真正有用的token
private String convertToken(String haeadToken) {
if (haeadToken == null || !haeadToken.startsWith(Prefix.TOKEN_BEARER)) {
return null;
}
return haeadToken.substring(7);
}
// 获取用户信息
public SecurityUser getUserDetails(DecodedJWT jwt) {
Map<String, Claim> claims = jwt.getClaims();
String authorities = claims.get("authorities").asString();
Set<SimpleGrantedAuthority> permissions = new HashSet<>();
for (String auth : authorities.split(",")) {
permissions.add(new SimpleGrantedAuthority(auth));
}
SecurityUser sysUser = new SecurityUser();
sysUser.setId(jwt.getClaim("id").asLong());
sysUser.setUsername(claims.get("username").toString());
sysUser.setPassword(claims.get("password").toString());
sysUser.setStatus(0);
sysUser.setAuthorities(permissions);
return sysUser;
}
// 获取用户ID
public Long getUid(DecodedJWT jwt) {
return jwt.getClaim("id").asLong();
}
}