本文主要是介绍Spring Security介绍及配置实现代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《SpringSecurity介绍及配置实现代码》SpringSecurity是一个功能强大的Java安全框架,它提供了全面的安全认证(Authentication)和授权(Authorizatio...
简介
Spring Security是一个功能强大的Java安全框架,它提供了全面的安全认证(Authentication)和授权(Authorization)的支持
与RBAC模型结合使用时,Spring Security能够实现灵活权限控制
Spring Security配置
Spring Security的配置类是实现安全控制的核心部分
开启Spring Security各种功能,以确保Web应用程序的安全性,包括认证、授权、会话管理、过滤器添加等
配置实现代码
com.sky.framework.config.SecurityConfig
package com.sky.framework.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.sprinphpgframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.web.filter.CorsFilter; import com.sky.framework.config.properties.PermitAllUrlProperties; import com.sky.framework.security.filter.JwtAuthenticationTokenFilter; import com.sky.framework.security.handle.AuthenticationEntryPointImpl; import com.sky.framework.secuhttp://www.chinasem.cnrity.handle.LogoutSuccessHandlerImpl; /** * spring security配置 * * @author ruoyi */ //开启方法级别的权限控制 @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { /** * 自定义用户认证逻辑 */ @Autowired private UserDetailsService userDetailsService; /** * 认证失败处理类 */ @Autowired private AuthenticationEntryPointImpl unauthorizedHandler; /** * 退出处理类 */ @Autowired private LogoutSuccessHandlerImpl logoutSuccessHandler; /** * token认证过滤器 */ @Autowired private JwtAuthenticationTokenFilter authenticationTokenFilter; /** * 跨域过滤器 */ @Autowired private CorsFilter corsFilter; /** * 允许匿名访问的地址 */ @Autowired private PermitAllUrlProperties permitAllUrl; /** * 解决 无法直接注入 AuthenticationManager * * @return * @throws Exception */ @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } /** * anyRequest | 匹配所有请求路径 * Access | SpringEl表达式结果为true时可以访问 * anonymous | 匿名可以访问 * denyAll | 用户不能访问 * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 * hasRole | 如果有参数,参数表示角色,则其角色可以访问 * permitAll | 用户可以任意访问 * rememberMe | 允许通过remember-me登录的用户访问 * authenticated | 用户登录后可访问 */ @Override protected void configure(HttpSecurity httpSecurity) throws Exception { // 注解标记允许匿名访问的url ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests(); permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll()); httpSecurity // CSRF禁用,因为不使用session .csrf().disable() // 禁用HTTP响应标头 .headers().cacheControl().disable().and() // 认证失败处理类 .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() // 基于token,所以不需要session .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() // 过滤请求 .authorizeRequests() // 对于登录login 注册register 验证码captchaImage 允许匿名访问 .antMatchers("/login", "/register", "/captchaImage").permitAll() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated() .and() .headers().frameOptions().disable(); // 添加Logout filter httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); // 添加JWT filter httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // 添加CORS filter httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class); httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); } /** * 强散列哈希加密实现 */ @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } /** * 身份认证接口 */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); } }
com.sky.framework.config.properties.PermitAllUrlProperties
package com.sky.framework.config.properties; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; import org.apache.commons.lang3.RegExUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import com.sky.common.annotation.Anonymous; /** * 设置Anonymous注解允许匿名访问的url * * @author ruoyi */ @Configuration public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware { //定义一个静态的正则表达式模式,用于匹配路径变量 private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); //应用上下文对象,用于获取spirng bean private ApplicationContext applicationContext; //存储允许匿名访问的URL模式的列表 private List<String> urls = new ArrayList<China编程;>(); //通配符,用于替换路径中的变量部分 public String ASTERISK = "*"; //在属性设置之后执行初始化操作 //主要用于解析请求映射,找出标记为匿名访问的方法和控制器,并将其URL模式添加至urls列表中 @Override public void afterPropertiesSet() { //从应用上下文中获取RequestMappingHandlerMapping的实例 RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class); //获取所有处理器方法及其对应的请求映射信息 Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods(); //遍历所有请求映射信息 map.keySet().forEach(info -> { HandlerMethod handlerMethod = map.get(info); // 获取方法上边的注解 Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class); // 如果方法上有Anonymous注解 将方法上的url添加至urls Optional.ofNullable(method).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns()) .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK)))); // 获取类上边的注解 Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class); //如果控制类上有Anonymous注解 将类下方法上的url添加至urls Optional.ofNullable(controller).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns()) .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK)))); }); } @Override public void setApplicationContext(ApplicationContext context) throws BeansException { this.applicationContext = context; } public List<String> getUrls() { return urls; } public void setUrls(List<String> urls) { this.urls = urls; } }
com.sky.framework.security.handle.AuthenticationEntryPointImpl
package com.sky.framework.security.handle; import java.io.IOException; import java.io.Serializable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; import com.alibaba.fastjson2.JSON; import com.sky.common.constant.HttpStatus; import com.sky.common.core.domain.AJAXResult; import com.sky.common.utils.ServletUtils; import com.sky.common.utils.StringUtils; /** * 认证失败处理类 返回未授权 * * @author ruoyi */ @Component public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable { private static final long serialVersionUID = -8970718410437077606L; /** * 处理未通过身份验证的请求 * 当用户尝试访问需要身份验证的资源但未通过认证时,此方法被调用 * 它向客户端放回一个包含错误信息的HTTP响应,指示认证失败 * @param request 请求对象,包含用户尝试访问的URI等信息 * @param response 响应对象,用于向客户端发送错误信息 * @param e 身份验证异常对象,指示用户身份验证失败的原因 * @throws IOException 如果在向客户端发送响应时发生输入输出错误 * */ @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException { //HTTP状态码401,表示未授权 int code = HttpStatus.UNAUTHORIZED; //构建错误信息,包含尝试访问的URI String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); //使用JSON格式向客户端返回错误信息 ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg))); } }
com.sky.framework.security.handle.LogoutSuccessHandlerImpl
package com.sky.framework.security.handle; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import com.alibaba.fastjson2.JSON; import com.sky.common.constant.Constants; import com.sky.common.core.domain.AjaxResult; import com.sky.common.core.domain.model.LoginUser; import com.sky.common.utils.MessageUtils; import com.sky.common.utils.ServletUtils; import com.sky.common.utils.StringUtils; import com.sky.framework.manager.AsyncManager; import com.sky.framework.manager.factory.AsyncFactory; import com.sky.framework.web.service.TokenService; /** * 自定义退出处理类 返回成功 * * @author ruoyi */ @Configuration public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { @Autowired private TokenService tokenService; /** * 退出处理 * * @return */ @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse responseChina编程, Authentication authentication) throws IOException, ServletException { //获取当前登录用户 LoginUser loginUser = tokenService.getLoginUser(request); //检查用户是否已登录 if (StringUtils.isNotNull(loginUser)) { //获取用户名 String userName = loginUser.getUsername(); // 删除用户缓存记录,实现退出 tokenService.delLoginUser(loginUser.getToken()); // 记录用户退出日志 AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success"))); } //向客户端返回退出成功的消息 ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success")))); } }
com.sky.framework.security.filter.JwtAuthenticationTokenFilter
package com.sky.framework.security.filter; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import com.sky.common.core.domain.model.LoginUser; import com.sky.common.utils.SecurityUtils; import com.sky.common.utils.StringUtils; import com.sky.framework.web.service.TokenService; /** * token过滤器 验证token有效性 * * @author ruoyi */ @Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { @Autowired private TokenService tokenService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { //通过令牌服务获取登录用户信息 LoginUser loginUser = tokenService.getLoginUser(request); //检查是否已登录且SS当前没有认证对象 if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) { //验证用户令牌是否有效 tokenService.verifyToken(loginUser); //创建认证对象 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); //设置认证对象的详细信息,这些详细信息是基于web的认证细节 authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); //将认证对象设置到安全上下文中,这样应用的其他部分可以访问到用户信息 SecurityContextHolder.getContext().setAuthentication(authenticationToken); } //继续执行过滤器链中的下一个过滤器或目标servlet chain.doFilter(request, response); } }
com.sky.framework.web.service.UserDetailsServiceImpl#loadUserByUsername
package com.sky.framework.web.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotatiopythonn.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.sky.common.core.domain.entity.SysUser; import com.sky.common.core.domain.model.LoginUser; import com.sky.common.enums.UserStatus; import com.sky.common.exception.ServiceException; import com.sky.common.utils.MessageUtils; import com.sky.common.utils.StringUtils; import com.sky.system.service.ISysUserService; /** * 用户验证处理 * * @author ruoyi */ @Service public class UserDetailsServiceImpl implements UserDetailsService { private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class); @Autowired private ISysUserService userService; @Autowired private SysPasswordService passwordService; @Autowired private SysPermissionService permissionService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //通过用户名查询用户信息 SysUser user = userService.selectUserByUserName(username); //检查用户是否存在 if (StringUtils.isNull(user)) { log.info("登录用户:{} 不存在.", username); //抛出异常提示用户不存在 throw new ServiceException(MessageUtils.message("user.not.exists")); } //检查用户是否已经被删除 else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { log.info("登录用户:{} 已被删除.", username); //抛出异常提示用户已经被删除 throw new ServiceException(MessageUtils.message("user.password.delete")); } //检查用户是否被停用 else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { log.info("登录用户:{} 已被停用.", username); //抛出异常提示用户已经被停用 throw new ServiceException(MessageUtils.message("user.blocked")); } //验证用户密码是否正确 passwordService.validate(user); //创建并返回登录用户对象 return createLoginUser(user); } public UserDetails createLoginUser(SysUser user) { return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user)); } }
到此这篇关于Spring Security介绍及配置实现代码的文章就介绍到这了,更多相关Spring Security介绍及配置内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!
这篇关于Spring Security介绍及配置实现代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!