菜鸟日记——Spring Security整合JWT的代码及流程详细解析(一,securityconfig部分)(超详细)


前言

1、此文适合刚刚开始学习的同学,欢迎指正.
2、当刚开始学习spring security整合JWT时总是无法分清楚JWT整合的具体过程,在网上找到的代码总是没有详细的注释,所以写了这样一篇文章,来记录。

备注:此文书写结构为先贴图或者代码,然后分析代码和内容,所以建议代码和下面分析的文字对比阅读


一、文件结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

整合JWT一共会使用 6个配置文件+各自的用户和权限文件(这里使用了5个表)
以上是会用到的文件除单文件外均使用红色框选出来,可以同下述文章对比查看

二、代码解析

1.securityConfig文件内容及分析

代码如下(示例):

/**
 * SpringSecurity的配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UmsAdminService adminService;
    @Autowired
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf()// 由于使用的是JWT,我们这里不需要csrf
                .disable()
                .sessionManagement()// 基于token,所以不需要session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js",
                        "/swagger-resources/**",
                        "/v2/api-docs/**"
                )
                .permitAll()
                .antMatchers("/admin/login", "/admin/register")// 对登录注册要允许匿名访问
                .permitAll()
                .antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
                .permitAll()
                .antMatchers("/**")//测试时全部运行访问
                .permitAll()
                .anyRequest()// 除上面外的所有请求全部需要鉴权认证
                .authenticated();
        // 禁用缓存
        httpSecurity.headers().cacheControl();
        // 添加JWT filter
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        httpSecurity.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthenticationEntryPoint);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //使用自定义省份验证组件
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new MyPasswordEncoder();
    }

    //获取用户信息
    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        //获取登录用户信息
        return new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                UmsMember adminByName = adminService.getAdminByName(username);
                if(adminByName!=null){
                    //查询用户的权限
                    List<UmsPermission> permissionList = adminService.getPermissionList(adminByName.getId());
                    return new MemberDetails(adminByName, permissionList);
                }
                throw new UsernameNotFoundException("用户名或密码错误");
            }
        };
    }

    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

    /**
     * 允许跨域调用的过滤器
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return new CorsFilter(source);
    }

    //将Spring Security自带的authenticationManager声明成Bean
    //声明它的作用是用它帮我们进行认证操作,调用这个Bean的authenticate方法会由Spring Security自动帮我们做认证。
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

1.1 代码分析

security配置文件中一共使用了7个方法:
方法一:configure(HttpSecurity httpSecurity)
1、此方法中主要定义了JWT过滤器
httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);

这一句话将JWT的过滤类添加到了security的过滤规则UsernamePasswordAuthenticationFilter之后;
采用的是addFilterBefore这个方法,这个方法和addFilter以及addFilterAfter类似;分别是将自定义的过滤器添加在某个过滤器之前/之后/相等的位置;
在这里插入图片描述
上图中绿色部分就是spring security自带的过滤器,而使用addFilter等方法就是将我们自定义的过滤器加入自带过滤器的队列中;
而本身的UsernamePasswordAuthenticationFilterBasicAuthenticationFilter是需要手动开启的,而在这里我们没有使用,所以使用addFilter添加在哪个位置不影响。

2、加入自定义返回类
httpSecurity.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthenticationEntryPoint);

返回类内容:

/**
 * 当未登录或者token失效访问接口时,自定义的返回结果
 * https://gitee.com/zscat-platform/mall on 2018/5/14.
 */
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println(JsonUtil.objectToJson(自己封装的统一返回类(authException.getMessage())));
        response.getWriter().flush();
    }
}
/**
 * 当访问接口没有权限时,自定义的返回结果
 */
@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException e) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println(JsonUtil.objectToJson(自己封装的统一返回类(e.getMessage())));
        response.getWriter().flush();
    }
}

方法二、configure(AuthenticationManagerBuilder auth)
1、此方法中主要配置自定义的加密类
//使用自定义省份验证组件
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());

在springboot 2.x之前好像是可以使用自带的加密方式,springbbot2.x之后好像就必须自定义加密方式了,具体还没有了解到,欢迎补充。
其中passwordEncoder调用的方法三


方法三:自定义加密类
1、此方法中导入自定义的加密类
@Bean
    public PasswordEncoder passwordEncoder() {
        return new MyPasswordEncoder();
    }

使用方式由方法二中调用


方法四:userDetailsService()
此类用于获取用户信息和比对用户数据
return new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                UmsMember adminByName = adminService.getAdminByName(username);
                if(adminByName!=null){
                    //查询用户的权限
                    List<UmsPermission> permissionList = adminService.getPermissionList(adminByName.getId());
                    return new MemberDetails(adminByName, permissionList);
                }
                throw new UsernameNotFoundException("用户名或密码错误");
            }
        };

此类方法有些喜欢单独定义一个类来使用,这里是写在一起,单独定义原理一样,只不过就是在return的时候调用一个继承了UserDetailsService的类


方法五:jwtAuthenticationTokenFilter()
1、此方法中主要导入JWT工具类
@Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

此方法中new了一个写好的JWT过滤类方法,在方法1中添加JWT过滤时引入

总结

本文章分为3个模块,这是第一个模块主要分析securityconfig部分

在构建小区物业管理系统时,权限控制和用户认证是保证系统安全性的关键环节。推荐参考《基于SpringBoot+Vue的小区物业管理系统开发》,该资源详细介绍了如何结合Spring Boot后端框架和Vue前端框架来实现个完整的系统。 参考资源链接:[基于SpringBoot+Vue的小区物业管理系统开发](https://wenku.youkuaiyun.com/doc/mg8y3y7e4m) 首先,Spring Security个强大的、可高度定制的身份验证和访问控制框架。它能为你的应用提供全面的安全保障。在小区物业管理系统中,你可以通过Spring Security来实现用户登录认证、权限分配以及防止CSRF攻击等功能。 实现用户认证的个常见做法是使用JWT(JSON Web Tokens)。JWT种简洁的、URL安全的方式,用于表示要在两方间传递的声明。结合Spring Security,可以在用户认证成功后生成JWT,并将其返回给前端。前端随后将JWT存储在客户端(通常是在localStorage中),并在每次发送请求时将其作为Bearer Token附加在请求头中。 在Spring Boot后端,你需要配置SecurityConfig类来集成Spring Security。在这个配置类中,你可以设置HTTP请求的安全规则,定义认证管理器(AuthenticationManager),并配置JWT认证过滤器。认证管理器负责处理用户的登录请求,而JWT认证过滤器则负责解析请求头中的JWT,并验证其有效性。 为了防止CSRF攻击,可以在Spring Security配置中关闭CSRF保护,因为在使用JWT的无状态认证机制中,CSRF攻击的风险可以被忽略。 此外,为了确保系统的用户权限可以按照预期工作,需要在数据库中定义相应的角色和权限,并在Spring Security配置中定义安全规则,如何将用户角色映射到特定资源的访问权限上。 通过上述步骤,你可以为小区物业管理系统提供个安全、高效且易于扩展的用户认证和权限控制机制。具体的代码实现和系统架构设计,可以详细参考《基于SpringBoot+Vue的小区物业管理系统开发》资源,它将为你提供更深入的理解和实践指导。 参考资源链接:[基于SpringBoot+Vue的小区物业管理系统开发](https://wenku.youkuaiyun.com/doc/mg8y3y7e4m)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值