ITPub博客

首页 > 数据库 > 数据库开发技术 > SpringBoot搭建Spring Security 入门

SpringBoot搭建Spring Security 入门

原创 数据库开发技术 作者:醉鱼Java 时间:2019-12-23 19:59:00 0 删除 编辑


简介

1. Spring Security 是一个提供身份验证,授权,保护以及防止常见攻击的框架,由于同时支持响应式和命令式,是spring框架的安全标准。

前提条件

  • jdk1.8+

例子使用SpringBoot版本 【2.0.5.RELEASE】,代码都是简写,只写关键代码,源码demo,文章底部github


1. 引入maven jar包(正常添加jar包依赖,只需保留第一步的jarbao,第三步第四步忽略即可)

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

2. 因为SpringBoot提供了BOM来管理版本,因此不需要指定版本,如果我们需要指定版本可以通过配置maven属性来配置

例

<properties>    <!-- ... -->    <spring-security.version>5.2.2.BUILD-SNAPSHOT</spring-security.version></dependencies>

3. 如果使用SNAPSHOT版本则需要定义Spring Snapshot存储库

<repositories>    <!-- ... possibly other repository elements ... -->    <repository>        <id>spring-snapshot</id>        <name>Spring Snapshot Repository</name>        <url>https://repo.spring.io/snapshot</url>    </repository></repositories>

4. 如果使用里程碑版本或者候选的版本,则需要指定Spring Milestone存储库

<repositories>    <!-- ... possibly other repository elements ... -->    <repository>        <id>spring-milestone</id>        <name>Spring Milestone Repository</name>        <url>https://repo.spring.io/milestone</url>    </repository></repositories>

5. application.properties 配置属性内容

# 启动端口server.port=8081# 启动项目路径server.servlet.context-path=/simple-security

6. 此时简单版的demo就已经完成了,访问http://127.0.0.1:8081会重定向到http://127.0.0.1:8081/simple-security/login 页面显示内容如下

7. 默认的用户名:user,密码为控制台打印的uuid

8.此时我们输入用户名密码之后验证通过了,但是会显示404,这是因为我们没有配置登录成功的首页,现在开始配置首页

9.新建一个WebSecurityConfig配置类,继承

WebSecurityConfigurerAdapter,此处配置关闭了csrf,支持表单登录,

拦截/login登录的请求,登录成功跳转login-success

代码如下

@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {        // 屏蔽csrf跨站        http.csrf().disable()
// 支持表单登录 .formLogin() // 登录逻辑处理url .loginProcessingUrl("/login") // 登录页面// .loginPage("login-view") //自定义成功登录页面 .successForwardUrl("/login-success"); }
/** * 密码验证方式 * NoOpPasswordEncoder.getInstance() 字符串校验 * @return */    @Bean public PasswordEncoder passwordEncoder(){ return NoOpPasswordEncoder.getInstance(); }}

10. 配置一个WebMvcConfig,重定向我们的url,实现登录逻辑处理

@Configurationpublic class WebMvcConfig implements WebMvcConfigurer {    @Override    public void addViewControllers(ViewControllerRegistry registry) {        registry.addViewController("/").setViewName("redirect:/login");    }}

11. 编写一个controller,作为登录成功之后的跳转

@RestControllerpublic class LoginController {    @RequestMapping("/login-success")    public String login(){        return "login success";    }}

12.此时启动项目,访问http://127.0.0.1:8081/simple-security/login,输入用户名user,密码(控制台打印的uuid)登录成功即可看到打印的login success

13. 自定义用户,实现UserDetailsService,此处我们生成的用户名是tz,密码就是123,我们实际使用中,可以根据用户名在数据库中查找返回,此处为了方便直接设置了一下,没有进行数据库查询。这样我们就成功配置了一个用户名tz密码123的账号,现在就来登录试一下吧

@Servicepublic class MyUserDetailService implements UserDetailsService {    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        UserDetails userDetails = User.withUsername("tz").password("123").build();        return userDetails;    }}

14.浏览器打开输入http://127.0.0.1:8081/simple-security/login

账号tz,密码123,点击login,登录成功跳转到我们刚才定义的controller,密码太简单了,我们平常不能直接使用明文密码啊,一般都是加密的,先看上面的WebSecurityConfig中我们定义了

PasswordEncoder的Bean 我们返回了一个
NoOpPasswordEncoder.getInstance()

这个代表进行简单的字符串匹配,也就是字符串相等就OK,我们下面配置另一个加密,BCryptPasswordEncoder(),修改我们的WebSecurityConfig


   /**     * 密码验证方式     * NoOpPasswordEncoder.getInstance() 字符串校验     * @return     */    @Bean    public PasswordEncoder passwordEncoder(){        return  new BCryptPasswordEncoder();    }


15.新建一个test类,生成我们的Bcrypt加密的密码,方便一会我们测试

@SpringBootTestpublic class SimpleSecurityApplicationTests {
@Test public void contextLoads() { String hashpw = BCrypt.hashpw("123", BCrypt.gensalt()); System.out.println(hashpw); } // 打印结果 $2a$10$pTffBwh9mawjeGG9K5ZhbenBfWQRV1aFVgZqVt59eM67iJhDqARyG   // 这个字符串就代表123,上面我们是使用的随机盐的方式,每次生成的密码都不一样,但是校验时原密码都是123 }

下面把打印的结果替换到我们的MyUserDetailService中

修改结果如下

  @Override    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserDetails userDetails = User.withUsername("tz").password("$2a$10$pTffBwh9mawjeGG9K5ZhbenBfWQRV1aFVgZqVt59eM67iJhDqARyG").build(); return userDetails; }


16. 启动项目,继续使用用户tz密码123登录,此时也是显示登录成功

17. 下面展示一下基本的授权

Controller中新增资源url

    @RequestMapping("/r/r1")    public String r1(){        return "r1";    }    @RequestMapping("/r/r2")    public String r2(){        return "r2";    }

WebSecurityConfig增加对资源的拦截,此处访问/r/r1需要p1权限,访问/r/r2需要p2权限

 // 屏蔽csrf跨站        http.csrf().disable()                .authorizeRequests()                // 拦截/r/**请求需要认证                .antMatchers("/r/r1").hasAuthority("p1")                .antMatchers("/r/r2").hasAuthority("p2")                .antMatchers("/r/**").authenticated()//                // 除了/r/** 其他都可以访问                .anyRequest().permitAll()                .and()                // 支持表单登录                .formLogin()                // 登录逻辑处理url                .loginProcessingUrl("/login")
//自定义成功登录页面 .successForwardUrl("/login-success"); }

MyUserDetailService中给tz用户增加p1权限

   @Override    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {        UserDetails userDetails = User.withUsername("tz").password("$2a$10$pTffBwh9mawjeGG9K5ZhbenBfWQRV1aFVgZqVt59eM67iJhDqARyG").authorities("p1").build();        return userDetails;    }

18.此时基本的权限拦截就完成了,如需更复杂的请参考官网验证,下面演示一下浏览器访问http://127.0.0.1:8081/simple-security/login使用用户名tz密码123来进行登录

修改为r1的访问url,访问查看我们 已经读取到r1 的资源

修改为r2的访问URL,访问查看我们已经被拒绝,显示403,因为我们只有p1权限,访问r1需要p1权限,所以我们可以访问,访问r2需要p2权限,我们没有p2权限,所以拒绝我们的访问

19. 好了入门教程到此结束了,如有错误欢迎指出

github demo地址 https://github.com/TianPuJun/springboot-demo/tree/master/springboot-simple-security


官网 https://spring.io/projects/spring-security


参考https://docs.spring.io/spring-security/site/docs/5.2.2.BUILD-SNAPSHOT/reference/htmlsingle/

原文作者:醉鱼Java;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-12-08

  • 博文量
    79
  • 访问量
    36657