dev #1
|
@ -0,0 +1,14 @@
|
||||||
|
package cn.bunny.common.constant;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Data
|
||||||
|
public class SecurityConstant {
|
||||||
|
public static String[] annotations = {"/", "/test/**", "/diagram-viewer/**", "/editor-app/**", "/*.html", "/admin/system/index/login", "/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v3/**", "/swagger-ui.html/**", "/doc.html"};
|
||||||
|
public static List<String> annotationsList = Arrays.asList(annotations);
|
||||||
|
}
|
|
@ -24,9 +24,7 @@ public class Result<T> {
|
||||||
*/
|
*/
|
||||||
protected static <T> Result<T> build(T data) {
|
protected static <T> Result<T> build(T data) {
|
||||||
Result<T> result = new Result<>();
|
Result<T> result = new Result<>();
|
||||||
if (data != null) {
|
|
||||||
result.setData(data);
|
result.setData(data);
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +54,7 @@ public class Result<T> {
|
||||||
Result<T> result = build(body);
|
Result<T> result = build(body);
|
||||||
result.setCode(code);
|
result.setCode(code);
|
||||||
result.setMessage(message);
|
result.setMessage(message);
|
||||||
|
result.setData(null);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
package cn.bunny.security.config;
|
package cn.bunny.security.config;
|
||||||
|
|
||||||
|
import cn.bunny.common.constant.SecurityConstant;
|
||||||
import cn.bunny.security.custom.CustomPasswordEncoder;
|
import cn.bunny.security.custom.CustomPasswordEncoder;
|
||||||
import cn.bunny.security.filter.TokenAuthenticationFilter;
|
import cn.bunny.security.filter.TokenAuthenticationFilter;
|
||||||
|
import cn.bunny.security.filter.TokenLoginFilter;
|
||||||
import cn.bunny.security.handelr.SecurityAccessDeniedHandler;
|
import cn.bunny.security.handelr.SecurityAccessDeniedHandler;
|
||||||
import cn.bunny.security.handelr.SecurityAuthenticationEntryPoint;
|
import cn.bunny.security.handelr.SecurityAuthenticationEntryPoint;
|
||||||
import cn.bunny.security.service.MyUserDetailsService;
|
import cn.bunny.security.service.CustomAuthorizationManagerService;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import cn.bunny.security.service.CustomUserDetailsService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.core.session.SessionRegistry;
|
import org.springframework.security.core.session.SessionRegistry;
|
||||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@EnableMethodSecurity
|
@EnableMethodSecurity
|
||||||
public class WebSecurityConfig {
|
public class WebSecurityConfig {
|
||||||
|
@Autowired
|
||||||
|
AuthenticationConfiguration authenticationConfiguration;
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
@Autowired
|
@Autowired
|
||||||
private MyUserDetailsService myUserDetailsService;
|
private CustomUserDetailsService customUserDetailsService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private CustomPasswordEncoder customPasswordEncoder;
|
private CustomPasswordEncoder customPasswordEncoder;
|
||||||
|
@Autowired
|
||||||
|
private CustomAuthorizationManagerService customAuthorizationManager;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
||||||
httpSecurity.authorizeHttpRequests(authorize -> {
|
httpSecurity
|
||||||
authorize.requestMatchers("/", "/test/**", "/diagram-viewer/**", "/editor-app/**", "/*.html", "/admin/system/index/login",
|
|
||||||
"/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v3/**", "/swagger-ui.html/**", "/doc.html").permitAll().anyRequest().authenticated();
|
|
||||||
})
|
|
||||||
// 前端段分离不需要---禁用明文验证
|
// 前端段分离不需要---禁用明文验证
|
||||||
.httpBasic(AbstractHttpConfigurer::disable)
|
.httpBasic(AbstractHttpConfigurer::disable)
|
||||||
// 前端段分离不需要---禁用默认登录页
|
// 前端段分离不需要---禁用默认登录页
|
||||||
|
@ -49,39 +49,35 @@ public class WebSecurityConfig {
|
||||||
.logout(AbstractHttpConfigurer::disable)
|
.logout(AbstractHttpConfigurer::disable)
|
||||||
// 前端段分离不需要---csrf攻击
|
// 前端段分离不需要---csrf攻击
|
||||||
.csrf(AbstractHttpConfigurer::disable)
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
// 跨域访问权限
|
// 跨域访问权限,如果需要可以关闭后自己配置跨域访问
|
||||||
.cors(AbstractHttpConfigurer::disable)
|
.cors(AbstractHttpConfigurer::disable)
|
||||||
// 前后端分离不需要---因为是无状态的
|
// 前后端分离不需要---因为是无状态的
|
||||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(AbstractHttpConfigurer::disable)
|
||||||
|
// 前后端分离不需要---记住我,e -> e.rememberMeParameter("rememberBunny").rememberMeCookieName("rememberBunny").key("BunnyKey")
|
||||||
|
.rememberMe(AbstractHttpConfigurer::disable)
|
||||||
|
.authorizeHttpRequests(authorize -> {
|
||||||
|
// 如果访问路径有下面的,不需要访问权限
|
||||||
|
authorize.requestMatchers(SecurityConstant.annotations).permitAll();
|
||||||
|
// 有样式文件,不需要访问权限
|
||||||
|
authorize.requestMatchers(RegexRequestMatcher.regexMatcher("^\\S*[css|js]$")).permitAll();
|
||||||
|
// 上面都不是需要鉴权访问
|
||||||
|
authorize.anyRequest().access(customAuthorizationManager);
|
||||||
|
})
|
||||||
.exceptionHandling(exception -> {
|
.exceptionHandling(exception -> {
|
||||||
// 请求未授权接口
|
// 请求未授权接口
|
||||||
exception.authenticationEntryPoint(new SecurityAuthenticationEntryPoint());
|
exception.authenticationEntryPoint(new SecurityAuthenticationEntryPoint());
|
||||||
// 没有权限访问
|
// 没有权限访问
|
||||||
exception.accessDeniedHandler(new SecurityAccessDeniedHandler());
|
exception.accessDeniedHandler(new SecurityAccessDeniedHandler());
|
||||||
})
|
})
|
||||||
// 记住我
|
|
||||||
.rememberMe(e -> e.rememberMeParameter("rememberBunny").rememberMeCookieName("rememberBunny").key("BunnyKey"))
|
|
||||||
// 自定义过滤器
|
// 自定义过滤器
|
||||||
// .addFilterAt(TokenLoginFilter(), UsernamePasswordAuthenticationFilter.class)
|
.addFilterBefore(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
|
||||||
// .addFilter(new TokenLoginFilter(redisTemplate))
|
.addFilterAt(new TokenLoginFilter(authenticationConfiguration, redisTemplate), UsernamePasswordAuthenticationFilter.class)
|
||||||
.addFilterBefore(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class);
|
// 自定义密码加密器和用户登录
|
||||||
|
.passwordManagement(customPasswordEncoder).userDetailsService(customUserDetailsService);
|
||||||
|
|
||||||
return httpSecurity.build();
|
return httpSecurity.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public AuthenticationProvider authenticationProvider() {
|
|
||||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
|
||||||
provider.setPasswordEncoder(customPasswordEncoder);
|
|
||||||
provider.setUserDetailsService(myUserDetailsService);
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public AuthenticationManager authenticationManager(@NotNull AuthenticationConfiguration config) throws Exception {
|
|
||||||
return config.getAuthenticationManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SessionRegistry sessionRegistry() {
|
public SessionRegistry sessionRegistry() {
|
||||||
return new SessionRegistryImpl();
|
return new SessionRegistryImpl();
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
package cn.bunny.security.custom;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
public class CustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
|
|
||||||
@Override
|
|
||||||
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
|
|
||||||
String token = object.getRequest().getHeader("token");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,6 +8,9 @@ import org.springframework.security.core.userdetails.User;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重写自带的User
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class CustomUser extends User {
|
public class CustomUser extends User {
|
||||||
|
|
|
@ -3,8 +3,11 @@ package cn.bunny.security.filter;
|
||||||
import cn.bunny.common.result.Result;
|
import cn.bunny.common.result.Result;
|
||||||
import cn.bunny.common.utils.JwtHelper;
|
import cn.bunny.common.utils.JwtHelper;
|
||||||
import cn.bunny.common.utils.ResponseUtil;
|
import cn.bunny.common.utils.ResponseUtil;
|
||||||
|
import cn.bunny.entity.system.Login;
|
||||||
import cn.bunny.enums.ResultCodeEnum;
|
import cn.bunny.enums.ResultCodeEnum;
|
||||||
import cn.bunny.security.custom.CustomUser;
|
import cn.bunny.security.custom.CustomUser;
|
||||||
|
import cn.bunny.security.handelr.SecurityAuthenticationFailureHandler;
|
||||||
|
import cn.bunny.security.handelr.SecurityAuthenticationSuccessHandler;
|
||||||
import cn.bunny.vo.system.LoginVo;
|
import cn.bunny.vo.system.LoginVo;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
@ -13,30 +16,36 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 由于SpringSecurity的登录只能是表单形式 并且用户名密码需要时username、password,可以通过继承 UsernamePasswordAuthenticationFilter 获取登录请求的参数
|
||||||
|
* 再去设置到 UsernamePasswordAuthenticationToken 中 来改变请求传参方式、参数名等 或者也可以在登录的时候加入其他参数等等
|
||||||
|
* 也可以在这里添加验证码、短信等的验证
|
||||||
|
*/
|
||||||
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
|
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
|
||||||
private final RedisTemplate<String, Object> redisTemplate;
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
// 构造方法
|
// 构造方法
|
||||||
public TokenLoginFilter(RedisTemplate<String, Object> redisTemplate) {
|
public TokenLoginFilter(AuthenticationConfiguration authenticationConfiguration, RedisTemplate<String, Object> redisTemplate) throws Exception {
|
||||||
|
this.setAuthenticationSuccessHandler(new SecurityAuthenticationSuccessHandler());
|
||||||
|
this.setAuthenticationFailureHandler(new SecurityAuthenticationFailureHandler());
|
||||||
this.setPostOnly(false);
|
this.setPostOnly(false);
|
||||||
// 指定登录接口及提交方式,可以指定任意路径
|
// 指定登录接口及提交方式,可以指定任意路径
|
||||||
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST"));
|
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST"));
|
||||||
|
this.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager());
|
||||||
this.redisTemplate = redisTemplate;
|
this.redisTemplate = redisTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录认证
|
// 登录认证
|
||||||
// 获取输入的用户名和密码,调用方法认证
|
// 获取输入的用户名和密码,调用方法认证
|
||||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||||
throws AuthenticationException {
|
|
||||||
try {
|
try {
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
|
LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
|
||||||
|
@ -60,9 +69,8 @@ public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
|
||||||
redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));
|
redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));
|
||||||
|
|
||||||
// 返回
|
// 返回
|
||||||
Map<String, Object> map = new HashMap<>();
|
Login login = Login.builder().token(token).build();
|
||||||
map.put("token", token);
|
ResponseUtil.out(response, Result.success(login));
|
||||||
ResponseUtil.out(response, Result.success(map));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 认证失败调用方法
|
// 认证失败调用方法
|
||||||
|
|
|
@ -3,16 +3,15 @@ package cn.bunny.security.handelr;
|
||||||
import cn.bunny.common.result.Result;
|
import cn.bunny.common.result.Result;
|
||||||
import cn.bunny.enums.ResultCodeEnum;
|
import cn.bunny.enums.ResultCodeEnum;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class SecurityAccessDeniedHandler implements org.springframework.security.web.access.AccessDeniedHandler {
|
public class SecurityAccessDeniedHandler implements org.springframework.security.web.access.AccessDeniedHandler {
|
||||||
|
@SneakyThrows
|
||||||
@Override
|
@Override
|
||||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
|
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) {
|
||||||
Result<Object> result = Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED);
|
Result<Object> result = Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED);
|
||||||
|
|
||||||
Object json = JSON.toJSON(result);
|
Object json = JSON.toJSON(result);
|
||||||
|
|
|
@ -3,7 +3,6 @@ package cn.bunny.security.handelr;
|
||||||
import cn.bunny.common.result.Result;
|
import cn.bunny.common.result.Result;
|
||||||
import cn.bunny.enums.ResultCodeEnum;
|
import cn.bunny.enums.ResultCodeEnum;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
@ -18,14 +17,20 @@ import java.io.IOException;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||||
@Override
|
@Override
|
||||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
|
||||||
String token = response.getHeader("token");
|
String token = response.getHeader("token");
|
||||||
String message = authException.getLocalizedMessage();
|
String message = authException.getMessage();
|
||||||
|
|
||||||
log.info("请求未认证接口:{},用户id:{}", message, token);
|
|
||||||
|
|
||||||
// 创建结果对象
|
// 创建结果对象
|
||||||
Result<Object> result = Result.error(ResultCodeEnum.FAIL_REQUEST_NOT_AUTH);
|
Result<Object> result;
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
result = Result.error(new Object(), ResultCodeEnum.LOGIN_AUTH);
|
||||||
|
log.info("请求未登录接口:{},用户id:{}", message, null);
|
||||||
|
} else {
|
||||||
|
result = Result.error(new Object(), ResultCodeEnum.LOGGED_IN_FROM_ANOTHER_DEVICE);
|
||||||
|
log.info("请求未授权接口:{},用户id:{}", message, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 返回响应
|
// 返回响应
|
||||||
response.setContentType("application/json;charset=UTF-8");
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package cn.bunny.security.handelr;
|
|
||||||
|
|
||||||
import cn.bunny.common.result.Result;
|
|
||||||
import cn.bunny.enums.ResultCodeEnum;
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.security.web.session.InvalidSessionStrategy;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class SecurityInvalidSessionStrategy implements InvalidSessionStrategy {
|
|
||||||
@Override
|
|
||||||
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
||||||
// 错误消息
|
|
||||||
Result<String> result = Result.error(ResultCodeEnum.SESSION_EXPIRATION);
|
|
||||||
|
|
||||||
// 转成JSON
|
|
||||||
Object json = JSON.toJSON(result);
|
|
||||||
|
|
||||||
// 返回响应
|
|
||||||
response.setContentType("application/json;charset=UTF-8");
|
|
||||||
response.getWriter().println(json);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package cn.bunny.security.handelr;
|
|
||||||
|
|
||||||
import cn.bunny.common.result.Result;
|
|
||||||
import cn.bunny.enums.ResultCodeEnum;
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 成功退出登录
|
|
||||||
*/
|
|
||||||
public class SecurityLogoutSuccessHandler implements LogoutSuccessHandler {
|
|
||||||
@Override
|
|
||||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
|
||||||
Result<Object> success = Result.success(ResultCodeEnum.SUCCESS_LOGOUT);
|
|
||||||
Object json = JSON.toJSON(success);
|
|
||||||
|
|
||||||
response.setContentType("application/json");
|
|
||||||
response.getWriter().println(json);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package cn.bunny.security.handelr;
|
|
||||||
|
|
||||||
import cn.bunny.common.result.Result;
|
|
||||||
import cn.bunny.enums.ResultCodeEnum;
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.security.web.session.SessionInformationExpiredEvent;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class SecuritySessionInformationExpiredStrategy implements org.springframework.security.web.session.SessionInformationExpiredStrategy {
|
|
||||||
@Override
|
|
||||||
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
|
|
||||||
// 创建结果对象
|
|
||||||
Result<Object> result = Result.error(ResultCodeEnum.THE_SAME_USER_HAS_LOGGED_IN);
|
|
||||||
|
|
||||||
// 转为JSON
|
|
||||||
Object json = JSON.toJSON(result);
|
|
||||||
|
|
||||||
// 返回响应
|
|
||||||
HttpServletResponse response = event.getResponse();
|
|
||||||
response.setContentType("application/json;charset=UTF-8");
|
|
||||||
response.getWriter().println(json);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package cn.bunny.security.service;
|
||||||
|
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||||
|
|
||||||
|
public interface CustomAuthorizationManagerService extends AuthorizationManager<RequestAuthorizationContext> {
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package cn.bunny.security.service;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
|
||||||
public interface MyUserDetailsService extends org.springframework.security.core.userdetails.UserDetailsService {
|
public interface CustomUserDetailsService extends org.springframework.security.core.userdetails.UserDetailsService {
|
||||||
/**
|
/**
|
||||||
* 根据用户名获取用户对象(获取不到直接抛异常)
|
* 根据用户名获取用户对象(获取不到直接抛异常)
|
||||||
*/
|
*/
|
|
@ -0,0 +1,36 @@
|
||||||
|
package cn.bunny.service.security;
|
||||||
|
|
||||||
|
import cn.bunny.security.service.CustomAuthorizationManagerService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义权限判断
|
||||||
|
* 判断用户有哪些权限
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class CustomAuthorizationManagerServiceImpl implements CustomAuthorizationManagerService {
|
||||||
|
@Override
|
||||||
|
public void verify(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
|
||||||
|
CustomAuthorizationManagerService.super.verify(authentication, requestAuthorizationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
|
||||||
|
String token = object.getRequest().getHeader("token");
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw new AccessDeniedException("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthorizationDecision(true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class MyUserDetailsService implements cn.bunny.security.service.MyUserDetailsService {
|
public class CustomUserDetailsService implements cn.bunny.security.service.CustomUserDetailsService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private SysUserMapper sysUserMapper;
|
private SysUserMapper sysUserMapper;
|
||||||
@Autowired
|
@Autowired
|
|
@ -3,7 +3,6 @@ package cn.bunny.service.service.impl;
|
||||||
import cn.bunny.common.constant.MessageConstant;
|
import cn.bunny.common.constant.MessageConstant;
|
||||||
import cn.bunny.common.service.exception.BunnyException;
|
import cn.bunny.common.service.exception.BunnyException;
|
||||||
import cn.bunny.common.utils.JwtHelper;
|
import cn.bunny.common.utils.JwtHelper;
|
||||||
import cn.bunny.common.utils.SnowflakeIdGenerator;
|
|
||||||
import cn.bunny.entity.system.Login;
|
import cn.bunny.entity.system.Login;
|
||||||
import cn.bunny.entity.system.SysUser;
|
import cn.bunny.entity.system.SysUser;
|
||||||
import cn.bunny.entity.system.SysUserinfo;
|
import cn.bunny.entity.system.SysUserinfo;
|
||||||
|
@ -16,7 +15,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.DigestUtils;
|
import org.springframework.util.DigestUtils;
|
||||||
|
|
||||||
|
@ -32,10 +30,6 @@ import org.springframework.util.DigestUtils;
|
||||||
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
|
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
@Autowired
|
|
||||||
private SnowflakeIdGenerator snowflakeIdGenerator;
|
|
||||||
@Autowired
|
|
||||||
private AuthenticationManager authenticationManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 登录
|
||||||
|
@ -69,10 +63,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||||
}
|
}
|
||||||
// 添加token
|
// 添加token
|
||||||
String token = JwtHelper.createToken(sysUser.getId(), sysUser.getUsername());
|
String token = JwtHelper.createToken(sysUser.getId(), sysUser.getUsername());
|
||||||
// UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(vo.getUsername(), vo.getPassword());
|
|
||||||
// Authentication authenticate = authenticationManager.authenticate(authentication);
|
|
||||||
// long snowId = snowflakeIdGenerator.nextId();
|
|
||||||
// redisTemplate.opsForValue().set(String.valueOf(snowId), authenticate);
|
|
||||||
return Login.builder().token(token).build();
|
return Login.builder().token(token).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue