Spring Security 安全框架概述 与 快速入门

目录

Spring Security 安全框架概述

Spring Security 快速入门

自定义默认账号名称与密码

内存用户认证与授权

Spring Security 用户注销


Spring Security 安全框架概述

1、Java web 应用中安全框架使用率高的莫过于 Spring-security 与 Apache Shiro。

1、Spring-security 官网:https://spring.io/projects/spring-security
2、Spring-security gitHub 开源地址:https://github.com/spring-projects/spring-security/

2、Spring Security 是 Spring 官网的顶级项目,与 spring boot、spring data、spring cloud 等齐名。

3、Spring Security 是一个专注于向 Java 应用程序提供身份验证和授权的安全框架,与所有 Spring 项目一样,Spring Security 的真正威力在于它可以很容易地扩展以满足定制需求。Spring Security 是采用 AOP 思想,基于 servlet 过滤器实现的。

4、Spring Security 是 Spring Boot 底层安全模块默认的技术选型,可以实现强大的 web 安全控制,对于安全控制,仅需引入spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理。

5、Spring Security Features(特性):

1、全面和可扩展的身份验证和授权支持(Comprehensive and extensible support for both Authentication and Authorization)
2、防止攻击,如会话固定,点击劫持,跨站请求伪造等(Protection against attacks like session fixation, clickjacking, cross site request forgery, etc)
3、Servlet API 的集成(Servlet API integration)
4、与 Spring Web MVC 的可选集成(Optional integration with Spring Web MVC )

认证 & 授权
应用程序安全的两个主要区域是“认证”和“授权”,spring security 的主要核心功能也是认证和授权。
 认证(Authentication)  用户认证指的是验证某个用户是否为系统中的合法主体,即用户能否访问该系统。用户认证一般要求用户提供账号和密码,系统通过校验账号和密码来完成认证过程。
授权(Authorization 用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限通常是不同的,比如有的用户只能读,有的用户能读能写。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。  
Web & 安全
 登陆/注销 HttpSecurity 配置登陆、注销功能
Thymeleaf 提供 SpringSecurity 标签支持

需要引入thymeleaf-extras-springsecurity4

sec:authentication=“name” 获得当前用户的用户名

sec:authorize=“hasRole(‘ADMIN’)” 当前用户必须拥有 ADMIN权 限时才会显示标签内容

remember me()

表单添加 remember-me 的 checkbox

配置启用 remember-me 功能

CSRF(Cross-site request forgery)跨站请求伪造 HttpSecurity 启用 csrf 功能,会为表单添加 _csrf 的值,提交携带来预防 CSRF

Spring Security 快速入门

1、环境:IDEA 14 + Java JDK 1.8 + Spring Boot 2.1.3.RELEASE +  Spring Security 5.1.4 + Apache Maven 3.5.2

2、pom.xml 文件中导入 Spring Security 依赖内容如下(官网 Spring Boot with Maven)



	org.springframework.boot
	spring-boot-starter-security

1、当没有导入 spring security 组件时,Spring boot 4 大静态资源目录下的资源以及 templates 下的 index.html 都可以从浏览器直接访问,但是一旦导入就无法直接访问了。(在线演示源码):

2、spring security 导入后默认已经开启了验证,必须先登录验证通过后才能访问(包括静态资源),当不做任何配置时,security 提供默认的账号为 "user"、登录的密码在应用启动时会随机生成并打印在控制台,格式如:Using generated security password: 4f4785b7-aadb-4aab-9b2f-d32749d06460

1、当用户未登录时,默认无论什么请求都会自动跳转到 Security 的 /login 进行登录操作,登录错误时会自动跳转到 /login?error,这些都是 Security 集成好了的。

2、默认的登陆页面使用的是在线的 bootstrap 样式,所以如果没有网络,则也就没有了样式。

官方文档:Java Configuration and Form Login

自定义默认账号名称与密码

1、导入 spring security 未做任何配置时,默认使用账号名称为 user,密码是启动时随机生成的,现在在全局配置文件中对它们进行修改。

2、在 spring boot 官网中可以找到如下 security properties 配置项:

# ----------------------------------------
# SECURITY PROPERTIES
# ----------------------------------------
# SECURITY (SecurityProperties)
spring.security.filter.order=-100 # Security filter chain order.
spring.security.filter.dispatcher-types=async,error,request # Security filter chain dispatcher types.
spring.security.user.name=user # Default user name.默认用户名为 user
spring.security.user.password= # Password for the default user name. 账号的密码,默认是自动随机生成
spring.security.user.roles= # Granted roles for the default user name. 默认用户角色

# SECURITY OAUTH2 CLIENT (OAuth2ClientProperties)
spring.security.oauth2.client.provider.*= # OAuth provider details.
spring.security.oauth2.client.registration.*= # OAuth client registrations.

# SECURITY OAUTH2 RESOURCE SERVER (OAuth2ResourceServerProperties)
spring.security.oauth2.resourceserver.jwt.jwk-set-uri= # JSON Web Key URI to use to verify the JWT token.
   spring.security.oauth2.resourceserver.jwt.issuer-uri= # URI that an OpenID Connect Provider asserts as its Issuer Identifier.

3、现在在 application.yml 文件配置如下(application.yml 也是同理):

spring:
  security:
    user:
      name: admin  # spring security 安全认证的默认账号与密码
      password: 123456

4、再次启动应用进行访问,此时必须使用配置好的账号与密码登录。

内存用户认证与授权

1、下面先使用内存用户来简单体验一下  Spring Security 的玩法,内存用户是指用户数据存储在内存中,区别于数据库用户。

2、新建一个 PersonControler,提供增删改查方法从浏览器访问,路径如下:

http://localhost:8080/person/findById/1     :根据 id 查询用户
http://localhost:8080/person/lists          :查询所有用户
http://localhost:8080/person/add              :添加用户
http://localhost:8080/person/update         :修改用户
http://localhost:8080/person/del/2             :删除用户

3、现在实现如下需求(用户 分配 角色,角色 分配 权限):

1、有 3 个用户:zhangSanFeng(张三丰) 、zhangCuiShan(张翠山)、zhangWuJi(张无忌)
2、有 3 个角色:administrators(管理员)、auditor(审核员)、operator(操作员)
3、角色对应的权限如下:
    3.1、administrators 能访问所有请求
    3.2、auditor 能查询、修改
    3.3、operator 能查询、添加
4、为 zhangSanFeng 分配 administrators 角色,zhangCuiShan 分配 auditor、operator 角色,zhangWuJi 分配 operator 角色 .

3、自定义类继承 WebSecurityConfigurerAdapter,然后重写 configure 方法配置认证与授权。

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
/**
 * spring security 安全框架配置
 * 1、 WebSecurityConfigurerAdapter(抽象类) implements 了 WebSecurityConfigurer
 * 2、@EnableWebSecurity :表示开启 Spring Security 安全认证与授权
 *
 * @author wangmaoxiong
 * @version 1.0
 * @date 2020/5/20 20:39
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 定义用户认证规则
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**inMemoryAuthentication():添加内存用户认证,这些账号密码只存储在内存中,而不是数据库。
         * jdbcAuthentication():JdbcUserDetailsManagerConfigurer 数据库用户认证。
         * 

* .passwordEncoder(PasswordEncoder passwordEncoder):密码编码,Spring Security 高版本必须进行密码编码,否则报错 * .withUser(String username):添加用户名称,返回 UserDetailsBuilder * .password(String password):为用户添加密码,不能为 null * .roles(String... roles):为用户添加角色,一个用户可以有多个角色. * .and():返回对象本身,方便链式编程,也可以分开写 *

*/ auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder()) .withUser("zhangSanFeng").password("123456").roles("administrators") .and() .withUser("zhangCuiShan").password("123456").roles("auditor", "operator") .and() .withUser("zhangWuJi").password("123456").roles("operator"); } /** * 定义授权规则 * * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { /** * .authorizeRequests:表示验证请求 * .antMatchers(String... antPatterns):使用 {@link AntPathRequestMatcher} 的匹配规则 * .antMatchers("/") : 表示应用的首页 * .permitAll():表示允许一切用户访问,底层调用 access("permitAll") * .hasRole(String role):表示 antMatchers 中的 url 请求允许此角色访问 * .hasAnyRole(String... roles) : 表示 antMatchers 中的 url 请求允许这多个角色访问 * .access(String attribute):表示允许访问的角色,permitAll、hasRole、hasAnyRole 底层都是调用 access 方法 * .access("permitAll") 等价于 permitAll() * "/**" 表示匹配任意 */ http.authorizeRequests().antMatchers("/").permitAll(); http.authorizeRequests() .antMatchers("/person/del/**").hasRole("administrators") .antMatchers("/person/update").hasAnyRole("administrators", "auditor") .antMatchers("/person/add").hasAnyRole("administrators", "operator") .antMatchers("/person/findById/**", "/person/lists").access("permitAll"); /** * http.authorizeRequests().anyRequest().hasRole("senior"): * 表示约定以外的所有请求,都需要有 senior 角色才可以访问 * http.authorizeRequests().anyRequest().authenticated(): * 表示约定以外的所有请求,必须要经过认证才能访问,但是认证的可以是任意角色,即只要认证就行,与角色的权限无关 * http.authorizeRequests().anyRequest().permitAll(): * 表示约定以外的所有请求,任何用户都可以访问. */ http.authorizeRequests().anyRequest().permitAll(); /** * formLogin:指定支持基于表单的身份验证 * 未使用 FormLoginConfigurer#loginPage(String) 指定登录页时,将自动生成一个登录页面,亲测此页面引用的是联网的 bootStrap 的样式,所以断网时,样式会有点怪 * 当用户没有登录、没有权限时就会自动跳转到登录页面(默认 /login) * 当登录失败时,默认跳转到 /login?error * 登录成功时会放行 */ http.formLogin(); } } /** * 密码编码。Spring Security 高版本必须进行密码编码,否则报错 */ class MyPasswordEncoder implements PasswordEncoder { @Override public String encode(CharSequence charSequence) { return charSequence.toString(); } @Override public boolean matches(CharSequence charSequence, String s) { return s.equals(charSequence.toString()); } }

1、关于 URL 地址的 AntPathRequestMatcher 匹配规则,可以参考官网文档:AntPathMatcher.html,其实和正则表达式的规则基本差不多。在线演示源码
2、Forbidden:不允许的,被禁止的。表示权限不足,这里因为没有配置错误页面,所以直接显示错误信息。
3、开启内存用户后,全局配置文件中 spring.security.user.name 与 password 配置用户会失效。

Spring Security 用户注销

1、使用 WebSecurityConfigurerAdapter 配置适配器时,会自动应用注销功能,默认情况下,访问 /logout 将通过以下方式注销用户:

使 HTTP 会话无效 清除已配置的所有 RememberMe(记住我) 身份验证
清除 SecurityContextHolder 重定向到 /login?logout

2、不过,与配置登录功能类似,可以使用各种选项进一步自定义注销要求,开启自动注销功能只需要设置 logout() 方法即可,下面是官方文档(Handling Logouts)给出的示例:

protected void configure(HttpSecurity http) throws Exception {
    http
        .logout()                                                               
            .logoutUrl("/my/logout")                                               
            .logoutSuccessUrl("/my/index")                                          
            .logoutSuccessHandler(logoutSuccessHandler)                             
            .invalidateHttpSession(true)                                            
            .addLogoutHandler(logoutHandler)                                        
            .deleteCookies(cookieNamesToClear)                                     
            .and()
        ...
}
logout 提供注销支持,使用 WebSecurityConfigurerAdapter 时会自动应用此选项,即不写时默认也支持注销功能
logoutUrl 触发注销的 URL(默认为 /logout),如果启用了 CSRF 保护(默认),则注销请求也必须是 POST。JavaDoc.
logoutSuccessUrl 注销后要重定向到的 URL, 默认值是 /login?logout. JavaDoc.
logoutSuccessHandler 自定义 LogoutSuccessHandler, 如果指定了此选项,则忽略 logoutSuccessUrl()
invalidateHttpSession 指定在注销时是否使 HttpSession 无效, 默认为 true.
addLogoutHandler 添加 LogoutHandler,默认情况下,SecurityContextLogoutHandler 将添加为最后一个 LogoutHandler
deleteCookies 允许指定退出成功时要删除的 cookie 的名称,这是显式添加 CookieClearingLogoutHandler 的快捷方式

一言以蔽之:默认开启了注销功能,默认以 "/logout" 路劲表示用户注销请求,注销成功后,默认跳转到 "/login?logout" 登录页面,自动清除 session,清除记住我功能的 Cookie,HttpSession 无效。

3、如下所示,前端提供一个用于注销的超链

  • 注销
  • 即可使用注销功能:

     

    你可能感兴趣的:(Spring,Security)