SecurityConfig配置


一、SecurityConfig

import com.example.anyimenchuang.common.handler.AccessDeniedHandlerImpl;
import com.example.anyimenchuang.common.handler.AuthenticationEntryPointImpl;
import com.example.anyimenchuang.handler.SecurityLogoutSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启权限注解功能
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Resource
    private AccessDeniedHandlerImpl accessDeniedHandler;

    @Resource
    private AuthenticationEntryPointImpl authenticationEntryPoint;
    @Resource
    private SecurityLogoutSuccessHandler securityLogoutSuccessHandler;

    //创建BCryptPasswordEncoder 注入容器 加密方式
    @Bean
    public PasswordEncoder passwordEncoder() {
        //当你将此对象注入容器时,就会自动将密码进行bc的比对校验。
        //如果输入的明文密码与数据库中的加密密码不匹配则报错。
        //切数据库中必须存储为bc加密的密码
        return new BCryptPasswordEncoder();
    }


    @Override   //配置登录的路径 及需要认证的路径
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//关闭csrf
                //不通过Session获取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 允许匿名访问
                .antMatchers("/user/add", "/user/login").anonymous()
                //放行swagger
                .antMatchers(
                        "/swagger-ui.html",
                        "/swagger-ui/index.html",
                        "/swagger-resources/**",
                        "/webjars/**",
                        "/swagger-ui/**",
                        "/v3/**",
                        "/api/**",
                        "/swagger-ui.html/**"
                ).permitAll()
//                .antMatchers("/hello").permitAll() //允许登录或者未登录都可访问
//                .antMatchers("/testCors").hasAuthority("system:dept:list222")
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated();

        http.logout()
                .logoutUrl("/user/logout")
                .logoutSuccessHandler(securityLogoutSuccessHandler)
                .deleteCookies("JSESSIONID");
        //添加过滤器
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        //配置异常处理器
        http.exceptionHandling()
                //配置认证失败及授权失败处理器
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);
        //设置跨越
        http.cors();

    }


    @Bean
    @Override  //需要通过AuthenticationManager的authenticate方法进行用户认证,所有需要在此将其注入容器
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}


二、其他配置

1.JwtAuthenticationTokenFilter

代码如下(示例):

import com.alibaba.fastjson2.JSON;
import com.example.anyimenchuang.common.LoginUser;
import com.example.anyimenchuang.common.utils.sys.JwtUtils;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;


/**
 * @Description : jwt认证过滤器  定义好后需要进行配置指定的位置 在SecurityConfig中进行配置
 * 当调用其他接口时需要携带token,此处进行token验证,验证通过则放行
 */
@Component //token校验过滤器
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        // 获取token
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {//如果为空
            //放行  因为后面还有其他的过滤器会进行判断并提示
            filterChain.doFilter(request, response);
            return;
        }
        // 解析token
        String userId;
        try {
            Claims claims = JwtUtils.parseJWT(token);
            userId = claims.getSubject();

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("token非法");
        }

        // 从redis中获取用户信息
        String redisKey = "user:" + userId;

        String value = redisTemplate.opsForValue().get(redisKey);
        LoginUser loginUser = JSON.parseObject(value, LoginUser.class);//会根据类型自动转换
        if (Objects.isNull(loginUser)) {
            throw new RuntimeException("用户未登录");
        }
        // 存入SecurityContextHolder
        // 获取权限信息封装到Authentication中  第三个为获取权限loginUser.getAuthorities()
        UsernamePasswordAuthenticationToken userToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(userToken);
        // 放行
        filterChain.doFilter(request, response);
    }
}

2.AccessDeniedHandlerImpl

代码如下(示例):

import com.alibaba.fastjson2.JSON;
import com.example.anyimenchuang.common.SysResult;
import com.example.anyimenchuang.common.utils.sys.WebUtils;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Description : 授权失败处理器
 */
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) {

        SysResult result = new SysResult().setCode(403).setMsg("您的权限不足");

        String json = JSON.toJSONString(result);
        //处理异常
        WebUtils.renderString(response, json);
    }
}


3.AccessDeniedHandlerImpl

代码如下(示例):

import com.alibaba.fastjson2.JSON;
import com.example.anyimenchuang.common.SysResult;
import com.example.anyimenchuang.common.utils.sys.WebUtils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Description : 自定义认证失败异常处理器
 */
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
        SysResult result = new SysResult().setCode(401).setMsg("用户认证失败请查询登录");
        String json = JSON.toJSONString(result);
        //处理异常
        WebUtils.renderString(response, json);
    }
}



4.AccessDeniedHandlerImpl

代码如下(示例):

import com.alibaba.fastjson2.JSON;
import com.example.anyimenchuang.common.JSONResult;
import com.example.anyimenchuang.common.utils.sys.JwtUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
public class SecurityLogoutSuccessHandler implements LogoutSuccessHandler {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Resource
    private RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();

    public SecurityLogoutSuccessHandler() {
    }

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException {

        String token = request.getHeader("token");
        int userId = Integer.parseInt(JwtUtils.parseJWT(token).getSubject());
        redisTemplate.delete("user:" + userId);

        logger.info("退出成功");

        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSON.toJSONString(new JSONResult<>(200, "success")));
    }
}



<think>好的,我现在要解决用户在Spring Security配置中遇到的CORS问题。用户提到参考了引用[1],其中提到了使用@CrossOrigin注解的方式,但可能他们在Spring Security环境下遇到了问题。首先,我需要回忆一下在Spring Security中配置CORS的方法,以及可能需要注意的事项。 首先,Spring Security的过滤器链可能会拦截请求,导致CORS配置失效。即使应用层面配置了CORS,如果Spring Security的配置没有正确处理预检请求(OPTIONS),仍然会出现跨域问题。因此,用户需要在SecurityConfig中显式地启用CORS支持,并确保相关的配置正确。 接下来,我应该考虑两种常见的配置方式:一种是使用Spring Security提供的CorsConfigurationSource,另一种是自定义过滤器。第一种方法更符合Spring Security的推荐做法,通过Bean定义CorsConfigurationSource,然后在配置中启用cors()。 另外,用户可能还需要处理特定的路径或HTTP方法的权限问题,例如预检请求OPTIONS需要被允许,否则即使CORS配置正确,请求还是会被拒绝。因此,在配置HttpSecurity时,需要确保antMatchers(HttpMethod.OPTIONS, "/**").permitAll(),这样预检请求不会被拦截。 可能出现的错误包括:未正确配置CorsConfigurationSource的allowedOrigins、methods等参数,或者忘记在SecurityConfig中调用cors()方法。此外,如果同时存在其他CORS配置(如@CrossOrigin注解或全局的WebMvcConfigurer),可能会引起冲突,需要确保配置的一致性。 最后,用户可能需要具体的代码示例来参考,所以需要提供一个SecurityConfig配置示例,包括CorsConfigurationSource的定义和HttpSecurity的配置。同时,提醒用户注意版本差异,比如不同Spring BootSpring Security版本中的配置方式可能略有不同,需要根据实际情况调整。</think>在Spring Security中配置跨域资源共享(CORS)时,需注意其过滤器链会覆盖其他CORS配置。以下是两种常用解决方案: ### 方案一:通过CorsConfigurationSource配置(推荐) ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .cors().configurationSource(corsConfigurationSource()) // 启用CORS配置 .and() .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 允许OPTIONS预检请求 // 其他安全配置... .and() .csrf().disable(); } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); // 允许的源 configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS")); // 允许的方法 configuration.setAllowedHeaders(Arrays.asList("*")); // 允许的请求头 configuration.setAllowCredentials(true); // 允许携带凭证 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); // 对所有路径生效 return source; } } ``` ### 方案二:自定义CORS过滤器 ```java @Bean public FilterRegistrationBean<CorsFilter> corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("http://localhost:3000"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source)); bean.setOrder(0); // 设置最高优先级 return bean; } ``` ### 常见问题解决 1. **预检请求被拦截** 确保配置包含`.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()` 2. **Credentials凭证问题** 当携带Cookie时需同时设置: ```java configuration.setAllowCredentials(true); configuration.setAllowedOrigins(Arrays.asList("http://trusted-domain.com")); // 不能使用通配符* ``` 3. **配置优先级冲突** 若同时存在多个CORS配置,需确保Spring Security的配置具有最高优先级[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值