欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > SpringBoot 整合 SpringSecurity

SpringBoot 整合 SpringSecurity

2024/10/25 20:21:16 来源:https://blog.csdn.net/baihaibo1024/article/details/131401058  浏览:    关键词:SpringBoot 整合 SpringSecurity

1. 项目目录

在这里插入图片描述

2. pom.xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.6.3</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>2.6.3</version>
</dependency>

3. 创建实体类

LoginForm

package com.cnbai.entity;/*** 登录参数*/
public class LoginForm {private String username;private String password;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

User

package com.cnbai.entity;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;/*** 实现 SpringSecurity 提供的 UserDetails 接口,保存登录信息*/
public class User implements UserDetails {private String username;private String password;/** 用户的权限集,默认需要添加前缀 */@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {ArrayList<SimpleGrantedAuthority> list  = new ArrayList<>();list.add(new SimpleGrantedAuthority("USER"));return list;}/** 用户的加密后的密码,不加密会使用前缀 */@Overridepublic String getPassword() {return password;}/** 应用内唯一的用户名 */@Overridepublic String getUsername() {return username;}/** 账户是否过期 */@Overridepublic boolean isAccountNonExpired() {return true;}/** 账户是否锁定 */@Overridepublic boolean isAccountNonLocked() {return true;}/** 凭证是否过期 */@Overridepublic boolean isCredentialsNonExpired() {return true;}/** 用户是否可用 */@Overridepublic boolean isEnabled() {return true;}
}

4. 创建拦截器

SessionInterceptor

package com.cnbai.intercepter;import com.cnbai.cache.RequestCache;
import com.cnbai.cache.SystemCache;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 自定义拦截器,所有请求之前优先判断 token*/
public class SessionInterceptor implements HandlerInterceptor {/*** 在处理请求之前被调用*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");if (token == null) {return false;}HttpSession session = SystemCache.getSession(token);if (session == null) {return false;}RequestCache.setSession(session);return true;}/*** 在处理请求之后,页面视图渲染之前被调用*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {RequestCache.cleanSession();}/*** 在处理请求完成且页面视图渲染完成后被调用*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("after...");}
}

5. 创建配置类

WebConfig

package com.cnbai.config;import com.cnbai.intercepter.SessionInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 实现 spring 拦截器,自定义拦截范围*/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SessionInterceptor()).addPathPatterns("/**").excludePathPatterns("/login");}
}

SystemConfig

package com.cnbai.config;import com.cnbai.cache.SystemCache;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** Spring容器启动之后,预加载资源,初始化 cache*/
@Configuration
@Order(1)
public class SystemConfig implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {SystemCache.init();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}

DiscoverSecurityConfig

package com.cnbai.config;import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;/*** SpringSecurity 配置类*/
@Configuration
@EnableWebSecurity
public class DiscoverSecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate UserDetailsService userDetailsService;@Resourceprivate PasswordEncoder passwordEncoder;/** 身份认证 */@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);}/** 认证管理 */@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManager();}/** 核心过滤器 */@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/resources/**").antMatchers("/static/**");}/** 安全过滤器链 */@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeHttpRequests().antMatchers("/**").permitAll().anyRequest().authenticated().and().exceptionHandling().accessDeniedPage("/404").and().csrf().disable();}
}

6. 创建缓存

SystemCache

package com.cnbai.cache;import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;/*** 枚举实现单例,维护全局缓存* eq: 缓存 token 和 session 的关系*/
public class SystemCache {/** 初始化 cache */public static void init() {SessionCache.SESSION_CACHE.init();}/** 获取 session */public static HttpSession getSession(String token) {return SessionCache.SESSION_CACHE.getSession(token);}/** 缓存 token 和 session 的关系 */public static void addSession(String token, HttpSession session) {SessionCache.SESSION_CACHE.add(token, session);}/** 清空 session */public static void clearSession(String token) {SessionCache.SESSION_CACHE.clearSession(token);}//====================================================================================private enum SessionCache {SESSION_CACHE;private final Map<String, HttpSession> cache;/** 初始化 cache */private void init() {cache = new HashMap<>(1);}/** 缓存 token 和 session 的关系 */private void add(String token, HttpSession session) {this.cache.put(token, session);}/** 获取 session */private HttpSession getSession(String token) {return this.cache.get(token);}/** 清空 session */private void clearSession(String token) {this.cache.remove(token);}}
}

RequestCache

package com.cnbai.cache;import com.cnbai.entity.User;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.http.HttpSession;/*** 用于存储鉴权用户,session 管理等,此类只维护每一次请求的缓存*/
public class RequestCache {private static final ThreadLocal<HttpSession> THREAD_LOCAL = new ThreadLocal<>();private static final String CURRENT_USER = "user";/** 添加 session 到 ThreadLocal */public static void setSession(HttpSession httpSession) {THREAD_LOCAL.set(httpSession);}/** 获取 session */public static HttpSession getHttpSession() {return THREAD_LOCAL.get();}/** 清空 session */public static void cleanSession() {THREAD_LOCAL.remove();}/** 添加 user 到 session */public static void setUser(User user) {getHttpSession().setAttribute(CURRENT_USER, user);}/** 获取 user */public static User getUser() {Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();if (principal instanceof User) {return (User) principal;} else {return (User) getHttpSession().getAttribute(CURRENT_USER);}}
}

7. 创建 Service

UserServiceImpl

package com.cnbai.service;import com.cnbai.cache.RequestCache;
import com.cnbai.cache.SystemCache;
import com.cnbai.entity.LoginForm;
import com.cnbai.entity.User;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;/*** 用户接口*/
public class UserServiceImpl {@Resourceprivate AuthenticationManager authenticationManager;/*** 登录*/public User login(LoginForm loginForm, HttpServletRequest request) {// 1. 通过 用户名 查询数据库用户信息User userDetail = queryByName(loginForm.getUsername());// 2. 验证密码UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetail, loginForm.getPassword());Authentication authenticate = authenticationManager.authenticate(authenticationToken);SecurityContextHolder.getContext().setAuthentication(authenticate);Object principal = authenticate.getPrincipal();if (principal instanceof User) {User user = (User) principal;RequestCache.setSession(request.getSession());RequestCache.setUser(user);}// 3. 缓存 token 和 session 的关系String token = UUID.randomUUID().toString().replaceAll("-", "");SystemCache.addSession(token, RequestCache.getHttpSession());// 4. 返回结果return RequestCache.getUser();}/*** 注销*/public void logout(HttpServletRequest request) {RequestCache.cleanSession();SecurityContextHolder.clearContext();SystemCache.clearSession(request.getHeader("token"));}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com