栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot——安全管理(一)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot——安全管理(一)

SpringBoot——安全管理

一、简介二、Spring Security

一、简介

安全可以说是公司的红线了,一般项目都有严格的认证和授权操作,在Java开发领域常见的安全框架有Shiro和Spring Security。Shiro是一个轻量级的安全管理框架,提供了认证、授权、会话管理、密码管理、缓存管理等功能,Spring Security是一个相对复杂的安全管理框架,功能比Shiro更加强大,权限控制细粒度更高,对OAuth2的支持也更好,又因为Spring Security源自Spring家族,因此可以和Spring框架无缝整合,特别是SpringBoot中提供的自动化配置方案,可以让Spring Security的使用更加便捷。

二、Spring Security

Spring Secuirty的基本配置
Spring Boot针对Spring Security提供了自动化配置方案,因此可以使Spring Security非常容易地整合进Spring Boot项目中,这也是在Spring Boot项目中使用Spring Security的优势。基本用法
基本整合步骤如下:

    创建项目,添加依赖
    常见一个Spring Boot Web项目,然后添加spring-boot-starter-security依赖即可,代码如下:
    
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
        
        
            org.springframework.boot
            spring-boot-starter-security
        
    添加hello接口
    接下来在项目中添加一个简单的/hello接口,内容如下:
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello";
    }
}
    启动项目测试
    接下来启动项目,启动成功后,访问/hello接口会自动跳转到登录页面,这个登录页面是由SpringSecurity提供的,如下图所示:

默认的用户名是user,默认的登录密码则在每次启动项目时随机生成,查看项目启动日志,如下图

配置用户名和密码
如果开发者对默认的用户名和密码不满意,可以在application.properties中配置默认的用户名、密码以及用户角色,配置方式如下:

spring.security.user.name=song
spring.security.user.password=123
spring.security.user.roles=admin

再次启动项目,项目启动日志就不会打印出随机生成的密码了,用户可以直接使用配置好的用户名和密码登录,登录成功后,用户还具有一个角色——admin。

基于内存的认证
可以自定义类继承自WebSecurityConfigurerAdaptor,进而实现对Spring Security更多的自定义配置,例如基于内存的认证,配置方式如下:

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                //配置用户admin 密码123 具备admin、user角色
                .withUser("admin").password("123").roles("ADMIN", "USER")
                .and()
                //配置用户song 密码123 具备user角色
                .withUser("song").password("123").roles("USER");
    }
}

注意:

    Spring Security 5.* 中引入了多种密码加密方式。必须指定一种。基于内存的用户配置在配置角色时不需要添加“ROLE_”前缀。

HttpSecurity
虽然可以实现认证功能,但是受保护的资源都是默认的,而且也不能根据实际情况进行角色管理,如果要实现这些功能,就需要重写WebSecurityConfigurerAdapter中的另一个方法,代码如下:

@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("root").password("123").roles("ADMIN", "DBA")
                .and()
                //配置用户admin 密码123 具备admin、user角色
                .withUser("admin").password("123").roles("ADMIN", "USER")
                .and()
                //配置用户song 密码123 具备user角色
                .withUser("song").password("123").roles("USER");
    }

    public void configure(HttpSecurity http) throws Exception {
     http.authorizeRequests()
             .antMatchers("/admin
             .formLogin()
             .loginProcessingUrl("/login")
             .permitAll()
             .and()
             //表示关闭csrf
             .csrf()
             .disable();
    }
}

登录表单详细配置
目前前后端分离正在成为企业级应用开发的主流,在前后端分离的开发方式中,前后端的数据交互通过JSON进行,这时,登录成功后就不是页面跳转了,而是一段JSON提示。要实现这些功能,只需要继续完善上文的配置。代码如下:

@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("root").password("123").roles("ADMIN", "DBA")
                .and()
                //配置用户admin 密码123 具备admin、user角色
                .withUser("admin").password("123").roles("ADMIN", "USER")
                .and()
                //配置用户song 密码123 具备user角色
                .withUser("song").password("123").roles("USER");
    }

    public void configure(HttpSecurity http) throws Exception {
     http.authorizeRequests()
             .antMatchers("/admin
             .formLogin()
             //自定义登录页面
             .loginPage("/login_page")
             //表示登录请求处理接口,无论是自定义登录页面还是移动端登录,都需要使用该接口
             .loginProcessingUrl("/login")
             //认证所需的用户名和密码的参数名,默认用户名参数是username,密码参数是passwd,可以在这里自定义
             .usernameParameter("name")
             .passwordParameter("passwd")
             
             .successHandler(new AuthenticationSuccessHandler() {
                 @Override
                 public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                     Object principal = authentication.getPrincipal();
                     response.setContentType("application/json;charset=utf-8");
                     PrintWriter out = response.getWriter();
                     response.setStatus(200);
                     Map map = new HashMap<>();
                     map.put("status", 200);
                     map.put("msg", principal);
                     ObjectMapper om = new ObjectMapper();
                     out.write(om.writevalueAsString(map));
                     out.flush();
                     out.close();
                 }
             })
             
             .failureHandler(new AuthenticationFailureHandler() {
                 @Override
                 public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                     response.setContentType("application/json;charset=utf-8");
                     PrintWriter out = response.getWriter();
                     response.setStatus(401);
                     Map map = new HashMap<>();
                     map.put("status", 401);
                     if (exception instanceof LockedException) {
                         map.put("msg", "账户被锁定,登录失败");
                     } else if (exception instanceof BadCredentialsException) {
                         map.put("msg", "账户名或密码输入错误,登录失败!");
                     } else if (exception instanceof DisabledException) {
                         map.put("msg", "账户被禁用,登录失败!");
                     } else if (exception instanceof AccountExpiredException) {
                         map.put("msg", "账户已过期,登录失败!");
                     } else if (exception instanceof CredentialsExpiredException) {
                          map.put("msg", "密码已过期,登录失败!");
                     } else {
                         map.put("msg", "登录失败!");
                     }
                     ObjectMapper om = new ObjectMapper();
                     out.write(om.writevalueAsString(map));
                     out.flush();
                     out.close();
                 }
             })
             .permitAll()
                 .and()
             //表示关闭csrf
             .csrf()
             .disable();
    }


注销登录配置
如果想要注销登录,也只需要提供简单的配置即可。代码如下:

             //注销登录,表示开启注销登录的配置
             .logout()
             //表示配置注销登录请求URL为"/logout",默认为“/logout”
             .logoutUrl("/logout")
             //表示是否清楚身份认证信息,默认为true,表示清楚
             .clearAuthentication(true)
             //表示是否使Session失效,默认为true
             .invalidateHttpSession(true)
             
             .addLogoutHandler(new LogoutHandler() {
                 @Override
                 public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
                 }
             })
             
             .logoutSuccessHandler(new LogoutSuccessHandler() {
                 @Override
                 public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                     response.sendRedirect("/login_page");
                 }
             })

多个HttpSecurity
如果业务比较复杂,开发者也可以配置多个HttpSecurity,实现对WebSecurityConfigurerAdaptor的多次扩展,代码如下:


@Configuration
public class MultiHttpSecurityConfig {
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("123").roles("ADMIN", "USER")
                .and()
                .withUser("song").password("123").roles("USER");
    }

    @Configuration
    @Order(1)
    public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/admin
    @Secured("ROLE_ADMIN")
    public String admin() {
        return "hello admin";
    }

    
    @PreAuthorize("hasRole('ADMIN') and hasRole('DBA')")
    public String dba() {
        return "hello dba";
    }
    
    @PreAuthorize("hasAnyRole('ADMIN', 'DBA', 'USER')")
    public String user() {
        return "user";
    }
}

最后,在Controller中注入Service并调用Service中的方法进行测试。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/750283.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号