Spring Security

本文介绍了Spring Security的基本概念和优势,通过一个入门案例展示了如何配置和使用Spring Security,包括设置默认的用户名和密码以及自定义用户信息。接着讨论了CSRF防护和密码加密的重要性,尤其是Bcrypt算法在密码加密中的应用。最后,展示了如何从数据库动态获取用户信息,并使用注解进行权限控制,提高了系统的安全性和灵活性。
摘要由CSDN通过智能技术生成

SpringSecurity介绍

SpringSecurity是基于spring的一种声明式的安全框架,充分利用Spring的IOC,DI,与AOP功能,为应用系统提供声明式的安全访问控制功能。它包括了认证和授权,可以在web请求与调用方法时进行身份的认证和授权。

优势:
对身份验证和授权的全面性和可扩展性
防止攻击,如会话固定、跨站请求伪造、点击劫持…
Servlet API集成
与Spring Web MVC的可选集成…

它的最大的优势就在于高度的扩展性。

入门案例

入门

  • 导入依赖
   <dependencies>
        <!-- web起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- springBoot整合Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
    </dependencies>
  • 编写启动类
package com.ssy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MySecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySecurityApplication.class,args);
    }
}

  • 编写controller层
ackage com.ssy.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/login")
public class MySecurityController {
    @GetMapping("/hello")
    public String hello(){
        return "hello security";
    }
    @GetMapping("/say")
    public String say(){
        return "say security";
    }
    @GetMapping("/register")
    public String register(){
        return "register security";
    }
}

这样的话,一个简单的Spring Security就搞定了,接下来就交给测试
在这里插入图片描述
上图中的8080为端口号,那么在浏览器地址栏中输入 localhost:8080/login/hello,是访问不到的,而是直接跳转到到http://localhost:8080/login 这个登陆页面,
在这里插入图片描述

这是因为在pom文件中加入了

   <!-- springBoot整合Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

此时输入用户名user以及密码,那么密码是啥呢?在哪里呢?那我们可以看向idea的控制台
在这里插入图片描述

Using generated security password: a384f26f-74f9-4d57-9a68-caa6745c3bd2
是不是就是说明密码(password)是: a384f26f-74f9-4d57-9a68-caa6745c3bd2

然后我们现在就拥有了用户名与密码,输入
在这里插入图片描述
并点击Sign in,那么我们可以看到
在这里插入图片描述

在当前页面下,地址栏中的地址发生了改变
并在当前页面输出 hello security

这个输出的hello security就是我们在controller层中的MySecurityController类中的hello方法中的返回值

在上述的案例中,用户名与密码是由框架默认生成的,那么我们也可以指定用户名与密码

import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/*
*   认证配置
*
* */
@Configuration
//指示一个类声明一个或多个@Bean方法,并且可以由Spring容器处理,以便在运行时为这些bean生成BeanDefinition和服务请求
@EnableWebSecurity
//开启web认证
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    /*
    *构建了认证的信息
    *
    * */
    @Bean//将我们创建的对象放入spring容器中
    //配置UserDetailsService,用来指定用户访问
    public UserDetailsService userDetailsService(){
        //利用InMemoryUserDetailsManager在我内存中构建用户详情
        //InMemoryUserDetailsManager实现了UserDetailsManager接口,UserDetailsManager接口继承了UserDetailsService
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        //用户详情对象    用户、(明文)密码、角色
        inMemoryUserDetailsManager.createUser(User.withUsername("张轩杰").password("{noop}1234").authorities("P1","Role_ADMIE").build());

        inMemoryUserDetailsManager.createUser(User.withUsername("于晓彤").password("{noop}1234").authorities("O1","ROLE_SELLER").build());

        return inMemoryUserDetailsManager;
    }
}

运行时可以在控制中看出并没有显示密码

D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\bin\java.exe -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:D:\Java\Idea\Idea2018.3\lib\idea_rt.jar=14514:D:\Java\Idea\Idea2018.3\bin -Dfile.encoding=UTF-8 -classpath D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\charsets.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\deploy.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\access-bridge-64.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\cldrdata.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\dnsns.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\jaccess.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\jfxrt.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\localedata.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\nashorn.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\sunec.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\sunjce_provider.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\sunmscapi.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\sunpkcs11.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\ext\zipfs.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\javaws.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\jce.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\jfr.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\jfxswt.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\jsse.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\management-agent.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\plugin.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\resources.jar;D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\jre\lib\rt.jar;D:\File\WorkSpace\First\hello-world\spring-security\target\classes;D:\File\Repository\repository\org\springframework\boot\spring-boot-starter-web\2.3.4.RELEASE\spring-boot-starter-web-2.3.4.RELEASE.jar;D:\File\Repository\repository\org\springframework\boot\spring-boot-starter\2.3.4.RELEASE\spring-boot-starter-2.3.4.RELEASE.jar;D:\File\Repository\repository\org\springframework\boot\spring-boot-starter-logging\2.3.4.RELEASE\spring-boot-starter-logging-2.3.4.RELEASE.jar;D:\File\Repository\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\File\Repository\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\File\Repository\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\File\Repository\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\File\Repository\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\File\Repository\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\File\Repository\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\File\Repository\repository\org\springframework\spring-core\5.2.9.RELEASE\spring-core-5.2.9.RELEASE.jar;D:\File\Repository\repository\org\springframework\spring-jcl\5.2.9.RELEASE\spring-jcl-5.2.9.RELEASE.jar;D:\File\Repository\repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\File\Repository\repository\org\springframework\boot\spring-boot-starter-json\2.3.4.RELEASE\spring-boot-starter-json-2.3.4.RELEASE.jar;D:\File\Repository\repository\com\fasterxml\jackson\core\jackson-databind\2.11.2\jackson-databind-2.11.2.jar;D:\File\Repository\repository\com\fasterxml\jackson\core\jackson-annotations\2.11.2\jackson-annotations-2.11.2.jar;D:\File\Repository\repository\com\fasterxml\jackson\core\jackson-core\2.11.2\jackson-core-2.11.2.jar;D:\File\Repository\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.2\jackson-datatype-jdk8-2.11.2.jar;D:\File\Repository\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.2\jackson-datatype-jsr310-2.11.2.jar;D:\File\Repository\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.2\jackson-module-parameter-names-2.11.2.jar;D:\File\Repository\repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.4.RELEASE\spring-boot-starter-tomcat-2.3.4.RELEASE.jar;D:\File\Repository\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.38\tomcat-embed-core-9.0.38.jar;D:\File\Repository\repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;D:\File\Repository\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.38\tomcat-embed-websocket-9.0.38.jar;D:\File\Repository\repository\org\springframework\spring-web\5.2.9.RELEASE\spring-web-5.2.9.RELEASE.jar;D:\File\Repository\repository\org\springframework\spring-beans\5.2.9.RELEASE\spring-beans-5.2.9.RELEASE.jar;D:\File\Repository\repository\org\springframework\spring-webmvc\5.2.9.RELEASE\spring-webmvc-5.2.9.RELEASE.jar;D:\File\Repository\repository\org\springframework\spring-context\5.2.9.RELEASE\spring-context-5.2.9.RELEASE.jar;D:\File\Repository\repository\org\springframework\spring-expression\5.2.9.RELEASE\spring-expression-5.2.9.RELEASE.jar;D:\File\Repository\repository\org\springframework\boot\spring-boot-starter-security\2.3.4.RELEASE\spring-boot-starter-security-2.3.4.RELEASE.jar;D:\File\Repository\repository\org\springframework\spring-aop\5.2.9.RELEASE\spring-aop-5.2.9.RELEASE.jar;D:\File\Repository\repository\org\springframework\security\spring-security-config\5.3.4.RELEASE\spring-security-config-5.3.4.RELEASE.jar;D:\File\Repository\repository\org\springframework\security\spring-security-core\5.3.4.RELEASE\spring-security-core-5.3.4.RELEASE.jar;D:\File\Repository\repository\org\springframework\security\spring-security-web\5.3.4.RELEASE\spring-security-web-5.3.4.RELEASE.jar;D:\File\Repository\repository\org\projectlombok\lombok\1.18.12\lombok-1.18.12.jar;D:\File\Repository\repository\org\springframework\boot\spring-boot-autoconfigure\2.2.2.RELEASE\spring-boot-autoconfigure-2.2.2.RELEASE.jar;D:\File\Repository\repository\org\springframework\boot\spring-boot\2.3.4.RELEASE\spring-boot-2.3.4.RELEASE.jar com.ssy.MySecurityApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.4.RELEASE)

2021-08-21 17:18:19.679  INFO 2948 --- [           main] com.ssy.MySecurityApplication            : Starting MySecurityApplication on W10-20210820635 with PID 2948 (D:\File\WorkSpace\First\hello-world\spring-security\target\classes started by ssy in D:\File\WorkSpace\First\hello-world)
2021-08-21 17:18:19.683  INFO 2948 --- [           main] com.ssy.MySecurityApplication            : No active profile set, falling back to default profiles: default
2021-08-21 17:18:20.303  INFO 2948 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-08-21 17:18:20.308  INFO 2948 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-08-21 17:18:20.308  INFO 2948 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.38]
2021-08-21 17:18:20.351  INFO 2948 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-08-21 17:18:20.351  INFO 2948 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 638 ms
2021-08-21 17:18:20.501  INFO 2948 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@55b62629, org.springframework.security.web.context.SecurityContextPersistenceFilter@30f4b1a6, org.springframework.security.web.header.HeaderWriterFilter@66f66866, org.springframework.security.web.csrf.CsrfFilter@3b0f7d9d, org.springframework.security.web.authentication.logout.LogoutFilter@17f460bb, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@cda4919, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@4c7a078, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@a53bb6f, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@757f675c, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3e1162e7, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5298dead, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e63cad, org.springframework.security.web.session.SessionManagementFilter@4d666b41, org.springframework.security.web.access.ExceptionTranslationFilter@28f8e165, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4fbb001b]
2021-08-21 17:18:20.559  INFO 2948 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-08-21 17:18:20.657  INFO 2948 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-08-21 17:18:20.664  INFO 2948 --- [           main] com.ssy.MySecurityApplication            : Started MySecurityApplication in 1.282 seconds (JVM running for 1.789)

还是在浏览器地址栏输入http://localhost:8080/login/hello,还是直接跳转到http://localhost:8080/login 这个登陆页面,
在这里插入图片描述
我们只需要输入我们自己定义的用户名以及密码
在这里插入图片描述
单机Sign in之后会看到
在这里插入图片描述
,那么就说明我们的这个配置已完成,那么上面的代码是什么意思呢?
将UserDetailsService 放入到spring容器中,Spring Security会利用容器来获取用户的信息。用户的信息详情被暂时放在了InMemoryUserDetailsManager 实现类中,并分别创建了两个用户以及各自的密码、权限

登录成功后即可访问到全部资源

接下来进行授权的操作

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()//允许表单登录  /longin
                .and()
                .logout()//退出登录		/logout
                .and()
                .csrf().disable()//关闭跨站请求伪造 框架中国默认实现了跨站请求伪造
                .authorizeRequests() //开始配置授权信息
                .antMatchers("/register").permitAll() //不登录即可访问  开放访问 /register
                .antMatchers("/hello").hasAuthority("P1") //具有P1权限才可以访问
                .antMatchers("/say").hasRole("SELLER") //具有SELLER 角色才可以访问 hasRole判断角色,角色名称前缀必须是ROLE_,必须大写 默认省略仅限hasRole
                .anyRequest().authenticated(); //其他的登录之后就可以访问
    }

代码编写完毕后,测试运行,在浏览器输入http://localhost:8080/register 可以直接得到
在这里插入图片描述
http://localhost:8080/register加上logout可以得到
在这里插入图片描述
在地址栏输入http://localhost:8080/hello 会得到
在这里插入图片描述
然后输入用户名及密码
在这里插入图片描述
单机Sign in会得到
在这里插入图片描述
在地址栏输入http://localhost:8080/say会得到
在这里插入图片描述
该用户不具备指定的角色权限

  • 扩展

CSRF(Cross-site request forgery)跨站请求伪造,也被称为"One Click Attack"或者 Session Riding,通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。

像上面的案例,随着用户越来越多时,配置文件也会越来越多,麻烦也不是特别麻烦,也只不过是加点语句的问题,主要是容易引起冲突问题。所以引入了注解,利用注解控制权限

==注解方式控制权限

package com.ssy.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PreDestroy;

@RestController
public class MySecurityController {

    @PreAuthorize("hasAuthority('p1')")
    @GetMapping("/hello")
    public String hello(){
        return "hello security";
    }

    @PreAuthorize("hasRole('SELLER')")
    @GetMapping("/say")
    public String say(){
        return "say security";
    }
    @GetMapping("/register")
    public String register(){
        return "register security";
    }
}

package com.ssy.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/*
*   认证配置
*
* */
@Configuration
//指示一个类声明一个或多个@Bean方法,并且可以由Spring容器处理,以便在运行时为这些bean生成BeanDefinition和服务请求
@EnableWebSecurity
//开启web认证
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启注解控制权限
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    /*
    *构建了认证的信息
    *
    * */
    @Bean//将我们创建的对象放入spring容器中
    //配置UserDetailsService,用来指定用户访问
    public UserDetailsService userDetailsService(){
        //利用InMemoryUserDetailsManager在我内存中构建用户详情
        //InMemoryUserDetailsManager实现了UserDetailsManager接口,UserDetailsManager接口继承了UserDetailsService
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        //用户详情对象    用户、(明文)密码、角色
        inMemoryUserDetailsManager.createUser(User.withUsername("张轩杰").password("{noop}1234").authorities("P1","ROLE_ADMIN").build());

        inMemoryUserDetailsManager.createUser(User.withUsername("于晓彤").password("{noop}1234").authorities("O1","ROLE_SELLER").build());

        return inMemoryUserDetailsManager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()//允许表单登录  /longin
                .and()
                .logout()//退出登录		/logout
                .and()
                .csrf().disable()//关闭跨站请求伪造 框架中国默认实现了跨站请求伪造
                .authorizeRequests() //开始配置授权信息
                .antMatchers("/register").permitAll() //不登录即可访问  开放访问 /register
               /* .antMatchers("/hello").hasAuthority("P1") //具有P1权限才可以访问
                .antMatchers("/say").hasRole("SELLER") //具有SELLER 角色才可以访问 hasRole判断角色,角色名称前缀必须是ROLE_,必须大写 默认省略仅限hasRole*/
                .anyRequest().authenticated(); //其他的登录之后就可以访问
    }
}

在使用@PreAuthorize注解时,需要开启全局方法授权开关,加上注解@EnableGlobalMethodSecurity(prePostEnabled=true)

经过演示,我们对于Spring Security框架有了一定的了解,但也有两个问题:

  • 1.密码采用的是明文方式,不安全
  • 2.用户名、密码直接通过程序硬编码,无法动态获取,不够灵活

密码加密

我们在这里对密码进行加密处理,保证一定的安全性

可逆加密算法

可逆加密算法就是在加密后, 密文可以反向解密得到密码原文;
1).对称加密
在这里插入图片描述

优点: 对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高。
缺点: 没有非对称加密安全。

常见的对称加密算法:DES、3DES、DESX、Blowfish、RC4、RC5、RC6和AES
2). 非对称加密

在这里插入图片描述
指加密和解密使用不同密钥的加密算法,也称为公私钥加密。假设两个用户要加密交换数据,双方交换公钥,使用时一方用对方的公钥加密,另一方即可用自己的私钥解密

私钥加密,持有私钥或公钥才可以解密
公钥加密,持有私钥才可解密

优点: 非对称加密与对称加密相比,其安全性更好;
缺点: 非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。

不可逆加密算法

一旦加密就不能反向解密得到密码原文 。通常用于密码数据加密。

常见的不可逆加密算法有: MD5 、SHA、HMAC

MD5与Bcrypt

MD5
比较常见的加密方式,通过MD5生成的密文,在大数据的背景下,是可以被破译的
在这里插入图片描述
可以在用户注册时,限制用户输入密码的长度及复杂度,从而增加破解难度

Bcrypt【加盐加密】

BCrypt 算法将 salt (盐值、随机匹配)随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理 salt 问题。

package com.ssy.test;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class MyPassWorld {
    public static void main(String[] args) {

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        for (int i = 0; i < 10; i++) {
            System.out.println(bCryptPasswordEncoder.encode("1234"));
        }
      
    }
}

得到结果:

$2a$10$TW5Cqkbu9qDR7fx/RG4aD.pGQ92qZJrC4o6gCbAOFiMQcs7E9hLCe
$2a$10$R8RLvpqrFdtcbyfm1Sb.UO.o940OshYEDaa6VjQQWXGVd6ijYuKvi
$2a$10$8nAcHAIV92cCffEThoKuPexvfQlBKIEjmtO4emjuImyxFBIV/HH6G
$2a$10$SMH6HzGX4rFkUKv5qMU73ucbHi4HZj9WPAaEhYLy.sXcIWy5DOUlK
$2a$10$eHxvEeaWB0GTdT63egeYAu/SN44KPamv8WAyusPVFuamxr8E8dLFa
$2a$10$3Yqkm.7YsXK20NmyxRvHF.xrpup4C.A9YV.YFs7wy0Dyhz0rpRVK6
$2a$10$eN4CH2Z9h56QsPFZDU0hGemdKbaiKsX23VTZzrF0D5e6CXac2IAAC
$2a$10$sDw39sN9vvkPIYIURdzXc.nfB4EN7yO387ZsDJbdx8JuEKO6xsYd6
$2a$10$O3/YDMINhU4fYgWnXQAGIuRr1FumfB7bTo4DeUVUauDXu7dLup5JG
$2a$10$efcRbvTDhYxAOeptJUlEkOn8eAolXlmXTf4SDbxnbx4GMdzzRtska

验证密码

   boolean matches = bCryptPasswordEncoder.matches("1234", "$2a$10$efcRbvTDhYxAOeptJUlEkOn8eAolXlmXTf4SDbxnbx4GMdzzRtska");
        if (matches){
            System.out.println("密码相同");
        }else {
            System.out.println("密码不相同");
        }
    }//返回值为true, 则代表验证通过; 反之, 验证不通过

得到

D:\Java\ActualRuntime\JDK\JDK\jdk_1.8\bin\java.exe 5.2.9.RELEASE.jar;D:\File\Repository\repository\org\springframework\spring-tx\5.2.9.RELEASE\spring-tx-5.2.9.RELEASE.jar com.ssy.test.MyPassWorld
密码相同

Process finished with exit code 0

将程序进行优化

动态获取数据库中的数据,将密码进行加密
yml文件

server:
  port: 8080
spring:
  application:
    name: spring-security
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: 1234
mybatis-plus:
  type-aliases-package: com.ssy.pojo
  configuration:
    map-underscore-to-camel-case: true

启动类

@SpringBootApplication
@MapperScan(basePackages = {"com.ssy.mapper"})//包扫描
public class MySecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySecurityApplication.class,args);
    }
}

pojo实体类

@Data
@TableName(value = "tb_user") //指定数据表
public class User {

    @TableId(type = IdType.AUTO)//自增
    private Integer id;
    private String username;
    private String password;
    private String roles;

}

controller层

package com.ssy.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class MySecurityController {

    @PreAuthorize("hasAuthority('p1')")
    @GetMapping("/hello")
    public String hello(){
        return "hello security";
    }

    @PreAuthorize("hasRole('SELLER')")
    @GetMapping("/say")
    public String say(){
        return "say security";
    }
    @GetMapping("/register")
    public String register(){
        return "register security";
    }
}

mapper层

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

config层

package com.ssy.config;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ssy.mapper.UserMapper;
import com.ssy.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

@Component //加载到spring容器
public class UserConfig implements UserDetailsService {

    @Autowired
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername,name);
        User user = userMapper.selectOne(lambdaQueryWrapper);

        System.out.println(user);

        return new org.springframework.security.core.userdetails.User(
                name,
                user.getPassword(),
                AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRoles()));
    }
}

package com.ssy.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/*
*   认证配置
*
* */
@Configuration
//指示一个类声明一个或多个@Bean方法,并且可以由Spring容器处理,以便在运行时为这些bean生成BeanDefinition和服务请求
@EnableWebSecurity
//开启web认证
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启注解控制权限
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean //将BCryptPasswordEncoder放入spring容器中
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

/*
    //配置密码加密器   加盐加密
    @Bean
    BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    *//*
    *构建了认证的信息
    *
    * *//*
    @Bean//将我们创建的对象放入spring容器中
    //配置UserDetailsService,用来指定用户访问
    public UserDetailsService userDetailsService(){
        //利用InMemoryUserDetailsManager在我内存中构建用户详情
        //InMemoryUserDetailsManager实现了UserDetailsManager接口,UserDetailsManager接口继承了UserDetailsService
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        //用户详情对象    用户、(明文)密码、角色
        inMemoryUserDetailsManager.createUser(User.withUsername("张轩杰").password("$2a$10$Lev2qXRsApjBO9pj8tEp9e8qeT.dx80P4gTUaXwTRQLcTk7.07Nm.").authorities("P1","ROLE_ADMIN").build());

        inMemoryUserDetailsManager.createUser(User.withUsername("于晓彤").password("$2a$10$Lev2qXRsApjBO9pj8tEp9e8qeT.dx80P4gTUaXwTRQLcTk7.07Nm.").authorities("O1","ROLE_SELLER").build());

        return inMemoryUserDetailsManager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()//允许表单登录  /longin
                .and()
                .logout()//退出登录		/logout
                .and()
                .csrf().disable()//关闭跨站请求伪造 框架中国默认实现了跨站请求伪造
                .authorizeRequests() //开始配置授权信息
                .antMatchers("/register").permitAll() //不登录即可访问  开放访问 /register
               *//* .antMatchers("/hello").hasAuthority("P1") //具有P1权限才可以访问
                .antMatchers("/say").hasRole("SELLER") //具有SELLER 角色才可以访问 hasRole判断角色,角色名称前缀必须是ROLE_,必须大写 默认省略仅限hasRole*//*
                .anyRequest().authenticated(); //其他的登录之后就可以访问
    }*/
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值