zoukankan      html  css  js  c++  java
  • Java架构师方案——Spring Security(一)快速入门(附完整项目代码)

    1.读完这篇文章你将免费获得一个SpringSecurity测试demo项目源码(可直接运行)。
    2.你将学到如何快速创建一个SpringSecurity项目,实现简单的登入功能,很方便的集成到Springboot项目。
    3.查看demo项目的运行测试效果,更具体地了解SpringSecurity功能。。

    什么是Spring Security


    Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。它支持众多的认证技术,如LDAP、基于IEFT RFC 的标准、Form-based authentication(简单用户接口)等等。概括就是:控制系统的登入拦截、用户登入认证、用户登入token的鉴权、系统api接口等资源的简单用户接口的权限控制。

    简单地说,就是系统的登入逻辑和代码实现不用自己开发,使用Spring Security进行配置化开发就可以。

    比较Spring Security登入业务与原生登入业务



    原生登入逻辑开发流程有:

    1)编写登入页面的form代码。

    2)编写登入controller接口代码。

    3)根据传入的用户名参数从数据库查询用户信息。

    4)比较查询出来的密码数据与传入的密码,相同则登入通过,否则登入失败。

    Spring Security登入逻辑开发流程:

    1)编写登入页面的form代码。

    2)Spring Security核心配置类开发。

    3)实现UserDetailsService接口,在loadUserByUsername方法实现用户信息的加载。

    为什么SpringSecurity登入业务开发工作量少



    SpringSecurity开发工作少,是因为它对登入业务进行了非常完整的建模,登入业务的整个过程中,需要开发者自己开发的局部逻辑不多,其中包括:自定义登入页面,自定义用户数据获取来源(UserDetailsService实现类)

    使用SpringSecurity来做系统的安全服务到底有多爽,下图代表了我此刻的内心。

    alt


    快速入门


    SpringBoot项目pom依赖

    这个是集成SpringSecurity所需要依赖的jar包。

    <!--security start-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    Springboot项目的pom文件中至少要包含上面两个依赖包。

    SpringSecurity配置类

    配置类要继承抽象类WebSecurityConfigurerAdapter,并使用注解@Configuration、@EnableGlobalMethodSecurity(prePostEnabled = true)修饰配置类。

    /**
     * @Author: Galen
     * @Date: 2019/3/27-14:43
     * @Description: spring-security权限管理的核心配置
     **/
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserSecurityService userSecurityService;
    
        /**
         * @Author: jackdking
         * @Description: 配置userDetails的数据源,密码加密格式
         * @Date: 2020/5/21-5:24
         * @Param: [auth]
         * @return: void
         **/
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userSecurityService)
                    .passwordEncoder(new BCryptPasswordEncoder());// 实现自定义登录校验
        }
    
        /**
         * @Author: Galen
         * @Description: 配置放行的资源
         * @Date: 2019/3/28-9:23
         * @Param: [web]
         * @return: void
         **/
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/login.html", "/index.html","/css/**", "/static/**", "/login_p", "/favicon.ico")
                    // 给 swagger 放行;不需要权限能访问的资源
                    .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/images/**", "/webjars/**", "/v2/api-docs", "/configuration/ui", "/configuration/security");
        }
    
        /**
         * @Author: Galen
         * @Description: 拦截配置
         * @Date: 2019/4/4-10:44
         * @Param: [http]
         * @return: void
         **/
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    // 使其支持跨域
                    .requestMatchers(CorsUtils :: isPreFlightRequest).permitAll()
                    // 其他路径需要授权访问
                    .anyRequest().authenticated()
    
                    .and()
                    .formLogin().loginPage("/login_p")// 设置登录页面,
                    //奇怪的是 这个url并没有被访问到。
                    .loginProcessingUrl("/login")// 自定义的登录接口,这个接口必须和你登入页面form的action地址一样。否则一直进入login_p页面:如果loginProcessingUrl不配置,默认是跟loginPage一样
                    .usernameParameter("username").passwordParameter("password")//告诉security form表单用户名和密码的参数表达式。
                    .failureHandler(new MyAuthenticationFailureHandler())// 这个失败处理 跟 failureUrl 配置是互斥的。 两种只选择一种
                    .successHandler(new MyAuthenticationSuccessHandler())//跟defaultSuccessUrl互斥 ,这个支持返回json数据。如果不设置这个成功后的处理器,则会报错 999。
    //                .defaultSuccessUrl("/index")   //跟successHandler配置互斥,这个支持重定向到成功页面。 访问指定页面,用户未登入,跳转至登入页面,如果登入成功,跳转至用户访问指定页面,用户访问登入页面,默认的跳转页面
    //                .failureUrl("/error_p") // 重定向失败页面   跟 failureHandler 配置是互斥的。 两种只选择一种
                    .permitAll()
    
                    .and()
                    .csrf().disable(); //关闭csrf
        }
    }
    • 配置类覆盖configure(AuthenticationManagerBuilder auth),设置用户信息来源接口userDetailsService的实现类,以及用户密码的加密实现对象BCryptPasswordEncoder。
    • 配置类覆盖configure(WebSecurity web),告知security框架哪些url不登入也能访问,例如一些css文件、js文件、登入页面等等。
    • 配置类覆盖configure(HttpSecurity http),告知security登入业务的一些信息,例如登录页面、自定义的登录接口、form表单用户名和密码的参数表达式、登入失败或成功的handler类。

    userDetailsService的开发

    在这个实现类中,security框架允许开发者自定义用户信息的来源:可以是在代码里面,或是数据库、缓存服务器、第三方服务等。在这个demo项目里,我们运用的比较简单,直接写死在代码中,创建了SecuritySysUser对象返回给Security。

    SecuritySysUser securityUser = new SecuritySysUser();
    securityUser.setUsername(username);
    securityUser.setPassword("$2a$10$4H1JSQxyrJlguu0/V4DnR.s2NBjE.k6rI6.W.1AFL0UEnR2IR2/5y");
    securityUser.setEnabled(true);
    
    List<SecuritySysRole> roles = new ArrayList<>();
    SecuritySysRole role = new SecuritySysRole();
    role.setNameCn("ROLE_ADMIN");
    securityUser.setRoles(roles);
    
    if (securityUser == null) {
        throw new UsernameNotFoundException("用户名不对");
    }
    
    log.info("用户信息:{}" , securityUser.toString());
    
    return securityUser;

    到这,使用security框架来开发用户登入业务结束了,那我们来看看运行效果。

    本文的demo项目获取方式在文章底部查看。

    右击项目文件com.jackdking.security.SpringSecurityApplication,选择Run As -> Java Application。

    浏览器输入http://localhost:9090,进入login登入页面。

    alt

    输入用户名/密码:admin/admin,点击登入按钮,然后查看返回的登入json信息。

    alt

    登入成功返回的json数据是security框架的登入成功处理器返回的结果:successHandler(new MyAuthenticationSuccessHandler())。

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        RespBean respBean = RespBean.ok("【MyAuthenticationSuccessHandler】登录成功!", SecurityUserUtil.getCurrentUser());
        new GalenWebMvcWrite().writeToWeb(request,response, respBean);
        System.out.println("【MyAuthenticationSuccessHandler】登录成功!");
    }

    输入错误的用户名和密码,返回的json信息,是错误处理器中的第一个异常错误类UsernameNotFoundException。

    alt

    登入失败返回的json数据是security框架的登入失败处理器返回的结果:failureHandler(new MyAuthenticationFailureHandler())。

     response.setContentType("application/json;charset=utf-8");
    RespBean respBean;
    if (exception instanceof BadCredentialsException ||
            exception instanceof UsernameNotFoundException) {
        respBean = RespBean.error("账户名或者密码输入错误!");
    } else if (exception instanceof LockedException) {
        respBean = RespBean.error("账户被锁定,请联系管理员!");
    } else if (exception instanceof CredentialsExpiredException) {
        respBean = RespBean.error("密码过期,请联系管理员!");
    } else if (exception instanceof AccountExpiredException) {
        respBean = RespBean.error("账户过期,请联系管理员!");
    } else if (exception instanceof DisabledException) {
        respBean = RespBean.error("账户被禁用,请联系管理员!");
    } else {
        respBean = RespBean.error("登录失败!");
    }
    
    System.out.println("失败逻辑处理。");
    //response.setStatus(401);
    new GalenWebMvcWrite().writeToWeb(request, response, respBean);

    作为架构师,当然希望系统能使用成熟的、功能特性丰富的安全服务框架,而security正是做好的选择。而且无论是从建设安全服务的人力、测试、运维、风险等成本角度考虑,security都是非常香的。

    Spring Security安全服务框架的配置化开发也大大提高了整个团队的开发效率,如果系统单独自己做一个安全服务框架,未来团队成员交接成本也会非常的高,也会伴随着较大的风险成本。

    查看更多 “Java架构师方案” 系列文章 以及 SpringBoot2.0学习示例

    完整的demo项目,请关注公众号“前沿科技bot“并发送"SEC-ONE"获取。

    alt

  • 相关阅读:
    FastDFS安装配置过程中出现错误提示"/home/yuqing/fastdfs" can't be accessed, error info: No such file or directory
    dubbo-monitor安装监控中心,管理控制台安装网页一直访问不到,解决bug的方式记录
    dubbo-monitor安装监控中心,管理控制台安装
    zookeeper伪分布式集群安装
    zookeeper单节点安装
    JedisCluster操作redis集群demo
    Redis Cluster集群的搭建
    redis3.0.6安装配置
    Windows注册表中修改CMD默认路径
    eclipse中使用mybatis-generator逆向代码生成工具问题解决记录
  • 原文地址:https://www.cnblogs.com/HelloWorld2016425/p/13959848.html
Copyright © 2011-2022 走看看