【框架】Spring Security 4

    xiaoxiao2022-07-06  196

    Spring Security开发安全的REST服务 https://www.bilibili.com/video/av54175861/

    备注: Spring Security太难上手了,找不到匹配Spring Boot 2.0的资料,改学Shiro,本文弃了。

    Spring Security

    http://projects.spring.io/spring-security/

    Spring Security is a powerful and highly customizable 【authentication】 and 【access-control】 framework.It is the de-facto standard for securing Spring-based applications.

    Spring Security 是功能强大,并高度可定制的【认证】和【访问控制】框架。 (只能用在Spring框架上)

    提问:Spring Security有什么功能?

    (1). Authentication 认证:说白了就是登录; (2). Authorization 授权:判断用户拥有什么权限,可以访问什么资源; (3). 安全防护,防止跨站请求(XSS攻击),Session攻击; (4). 非常容易结合Spring Boot;

    Spring Security 和 Apache Shiro的区别

    相同处: (Shiro有的功能,Spring Security基本都有) 1.认证功能 Authentication 2.授权功能 Authorization 3.加密功能 4.会话管理 5.缓存支持 6.RememberMe 功能

    不同处:

    Spring Security: 1.更易于Spring的开发,配置权限更方便;而Shiro需要和Spring整合开发; 2.更能比Shiro更丰富,例如安全防护; 3.社区资源比Shiro更丰富;

    Shiro: 1.配置和使用较简单;Spring Security上手更复杂(讽刺的是“Spring”是以简单闻名的); 2.依赖性低,不需要任何框架和容器,可独立运行;Spring Security依赖Spring框架;

    HttpBasic方式的权限实现

    FormLogin方式的权限实现

    Spring Security 执行原理分析

    自定义登录页面/请求

    user-service 配置实现用户权限访问控制

    自定义UserDetailService类实现用户权限访问控制

    Spring Boot + Spring Security

    快速搭建

    POM: SB父模版:

    <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>

    准备好启动类,Run成功;

    下一步:准备访问的资源:

    . . .

    整合Security - HttpBasic权限实现

    第一步:Spring Security 依赖

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

    第二步:编写配置类SecurityConfig

    整合Security - FormBasic权限实现

    自定义登录页面,自定义用户权限判断

    ——————————————————

    以前写的

    原理简介

    Spring Security的安全访问控制分为Authentication(认证)和Authorization(授权,也叫“访问控制”)。认证指的是用户登录的信息验证,判断你账号密码是否正确;授权指的是当用户访问一个页面时判断他有没有这个权限。

    一般流程为:

    ①当用户登录时,前端将用户输入的用户名、密码信息传输到后台,后台用一个类对象将其封装起来,通常使用的是UsernamePasswordAuthenticationToken这个类。

    ②程序负责验证这个类对象。验证方法是调用Service根据username从数据库中取用户信息到实体类的实例中,比较两者的密码,如果密码正确就成功登陆,同时把包含着用户的用户名、密码、所具有的权限等信息的类对象放到SecurityContextHolder(安全上下文容器,类似Session)中去。

    ③用户访问一个资源的时候,首先判断是否是受限资源。如果是的话还要判断当前是否未登录,没有的话就跳到登录页面。

    ④如果用户已经登录,访问一个受限资源的时候,程序要根据url去数据库中取出该资源所对应的所有可以访问的角色,然后拿着当前用户的所有角色一一对比,判断用户是否可以访问。

    https://www.bilibili.com/video/av47950439/?p=18

    若项目中有Security配置,项目默认是打开的;

    若想关闭,properties中写:security.basic.enable = false


    Spring Security是一款强大的安全认证服务框架; 它的原理就是在访问我们的系统前加了一系列的过滤器,可以称为过滤器链。 它的两大核心就是 认证 和 授权 ;

    1.添加依赖

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

    2.新建一个html页面,我这里建的是hello.html

    <html lang="en"> <head> <meta charset="UTF-8"/> <title>SpringSecurity</title> </head> <body> <h2>登录页面</h2> <form action="/admin/login" method="post"> 用户名:<input type="text" name="username" value=""/><br/> 密码:<input type="text" name="password" value=""/><br/> <button type="submit">登录</button> </form> </body> </html>

    3.目录结构: 4.在SpringSecurityApplication里配置访问html的controller

    @SpringBootApplication @RestController public class SpringSecurityApplication { public static void main(String[] args) { SpringApplication.run(SpringSecurityApplication.class, args); } @GetMapping("/hello") public String hello(){ return "hello"; } }

    然后访问http://localhost:8080/hello会出现如下的身份验证框:Spring Security 默认HTTP Basic登录 (在不进行配置的情况下,默认拦截所有的请求。)

    默认方式肯定不够!!!

    5.新建一个配置类MySecurityConfig,这个类需要继承WebSecurityConfigurerAdapter,然后重写他的configure方法,代码如下

    @Configuration public class MySecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() // 表单登录 // http.httpBasic() // 如果把上行去掉,只写这行,就会恢复HTTP Basic登录 .and() .authorizeRequests() // 对请求做授权 .anyRequest() // 任何请求 .authenticated(); // 都需要身份验证 } }

    于是浏览器访问页面变成了:表单验证

    自定义认证逻辑

    上面的页面是springsecurity默认的一个登录页面,我们可以配置自己的登录页面,以及自己的校验逻辑。配置自己的登录页面需要在配置类MySecurityConfig中指定登录页面,如下

    @Configuration public class MySecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // http.httpBasic() http.authorizeRequests() .antMatchers("/hello.html") .permitAll()//注意这里hello.html需要配置成不需要身份认证,否则会报重定向次数过多 .and() .formLogin() .loginPage("/hello.html")//指定我们自己的登录页面 .loginProcessingUrl("/admin/login")//指定让UsernamePasswordAuthenticationFilter拦截器拦截的路径 .defaultSuccessUrl("/index")//默认登录成功后跳转的页面 .and() .authorizeRequests() .anyRequest() .authenticated(); http.csrf().disable(); http.headers().frameOptions().sameOrigin(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }

    实战:Spring Boot + Spring Security

    1.快速初始化一个Spring Boot应用; 2.如何添加给予内存的用户鉴权功能; 3.如何添加基于角色的访问控制逻辑;

    两个基本概念: 这两概念在中文和英文语境下都非常相似;

    白话: 鉴权:判断用户具体身份; 授权:根据用户身份,判断其行为是否可以被执行;

    Authentication 鉴权 [ɔ,θɛntɪ'keʃən] 场景:游戏登录时,根据用户提交的用户名和密码来判断系统中用户的具体身份信息;

    Authorization 授权 [,ɔθərɪ'zeʃən] 场景:游戏时根据用户是不是XX等级用户,判断其是否可以参加相关VIP活动;

    Spring Boot启动成功,返回内容包括一句: Using generated security password: 53e117aa-3f89-4487-823b-184adce2e7ac

    浏览器登录:http://127.0.0.1:8080

    【三大终极问题】: 你是谁? 你从哪里来? 你要到哪里?

    这时,容易碰到此问题:(页面搜索) IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"


    报错

    IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" 即,在浏览器页面输入了用户名和密码,都无法登录,页面始终停留在要求登录的状态; public UserDetailsService userDetailsService(){ InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("user").password(new BCryptPasswordEncoder().encode("hello")).roles("USER"); return manager; } protected void configure(AuthenticationManagerBuilder auth) throws Exception { //inMemoryAuthentication 从内存中获取 auth.inMemoryAuthentication().withUser("user1").password("123456").roles("USER"); } protected void configure(AuthenticationManagerBuilder auth) throws Exception { //inMemoryAuthentication 从内存中获取 auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("user1").password(new BCryptPasswordEncoder().encode("123456")).roles("USER"); }
    最新回复(0)