Spring Security 概述 与 快速使用

目录

Spring Security 概述

Features(特性)

认证 & 授权

Web & 安全

快速使用

新建 spring boot 应用

新建页面与默认账号访问测试

application.yml 自定义默认账号与密码

内存用户认证与授权

UserControler 控制层访问

认证与授权


Spring Security 概述

1、Java web 应用中安全框架使用率高的莫过于:

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

Apache Shiro :http://shiro.apache.org/

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

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

Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements

4、Spring Security 是 Spring Boot 底层安全模块默认的技术选型,可以实现强大的 web 安全控制,对于安全控制,仅需引入spring-boot-starter-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 integration(Servlet API的集成)

4)Optional integration with Spring Web MVC (与Spring Web MVC的可选集成)

认证 & 授权

1、应用程序安全的两个主要区域是“认证”和“授权”,spring security 的主要核心功能也是认证和授权。

认证(Authentication

用户认证指的是验证某个用户是否为系统中的合法主体,即用户能否访问该系统。用户认证一般要求用户提供账号和密码,系统通过校验账号和密码来完成认证过程。

授权(Authorization

用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限通常是不同的,以一个为例,有的用户只能读,有的用户能读能写。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。  

Web & 安全

1、登陆/注销

-HttpSecurity 配置登陆、注销功能

2、Thymeleaf 提供 SpringSecurity 标签支持

需要引入thymeleaf-extras-springsecurity4

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

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

3、remember me

表单添加 remember-me 的 checkbox

配置启用 remember-me 功能

4、CSRFCross-site request forgery)跨站请求伪造

-HttpSecurity 启用 csrf 功能,会为表单添加 _csrf 的值,提交携带来预防 CSRF

快速使用

新建 spring boot 应用

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 文件自动生成内容如下,一共使用了 3 个组件:因为创建的是 web 应用,所以选择 web 组件,为了写html 页面方便,所以使用了 Thymeleaf 模板引擎,已经本文学习的 Security 安全组件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/>
        <!-- lookup parent from repository -->
    </parent>
    <groupId>www.wmx.com</groupId>
    <artifactId>spring-security-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-security-app</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- Spring security 安全组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- Thymeleaf 模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- web组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring boot 测试模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- spring security 测试模块-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3、当没有导入 spring security 组件时,4大静态资源目录下的资源以及 templates 下的 index.html 都可以从浏览器直接访问,但是一旦导入就无法直接访问了。

4、spring security 导入后默认已经开启了验证,必须先登录验证通过后才能访问,当不做任何配置时,security 提供默认的账号为 "user"、登录的密码在应用启动时会随机生成并打印在控制台,格式如下所示:

Using generated security password: 4f4785b7-aadb-4aab-9b2f-d32749d06460

新建页面与默认账号访问测试

1、Spring boot 应用默认情况下如下所示的 4 大静态资源目录下的资源,浏览器都可以直接访问。

"classpath:/META‐INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"

2、4 大静态资源目录下 .html 文件中无法使用 Thyemelaf 模板引擎,templates 模板目录下 .html 文件中可以使用。

3、templates 模板目录中的 .html 文件除了 index.html 可以直接访问外,其余的从浏览器都无法直接访问,必须通过后台才能访问,相当于以前的 WEB-INF目录下的文件无法直接访问一样。

4、现在在 resources/templates 下新建 index.html 页面,在 resources/static 下面新建 home.html,其余内容都默认。

5、下面启动 web 应用,可以在控制台看到如下信息:

...
2019-03-28 15:56:33.157  INFO 10924 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page template: index
2019-03-28 15:56:33.347  INFO 10924 --- [           main] .s.s.UserDetailsServiceAutoConfiguration : 
...
Using generated security password: 4f4785b7-aadb-4aab-9b2f-d32749d06460
...
2019-03-28 15:56:33.496  INFO 10924 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-03-28 15:56:33.499  INFO 10924 --- [           main] c.wmx.www.SpringSecurityAppApplication   : Started SpringSecurityAppApplication in 3.025 seconds (JVM running for 3.489)
...

6、如下所示当用户未登录时,会自动跳转到 Security 的 /login 进行登录操作,登录错误时会自动跳转到 /login?error,这些都是 Security 集成好了的。

application.yml 自定义默认账号与密码

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

2、在 spring boot 2.1.3 官网中可以找到如下 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.properties 文件配置如下(application.yml 也是同理):

#应用上下文路径
server.servlet.context-path=/ssApp
#服务器访问端口
server.port=80
#spring security 安全认证的默认账号与密码
spring.security.user.name=admin
spring.security.user.password=123456

4、再次启动应用进行访问:

5、此时必须使用配置好的账号与密码登录。

内存用户认证与授权

UserControler 控制层访问

1、实际中不可能直接访问 .html 文件,而是通过后台控制器处理后进行跳转或者返回,这里新建一个 UserControler,提供增删改查的四个方法来从浏览器访问。方法中只做简单模拟,并不操作数据库。

package com.wmx.www.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.Date;

/**
 * Created by Administrator on 2019/3/28 0028.
 * 用户控制层
 *
 * @RestController 注解是一个组合注解,相当于同时加了 @Controller、@ResponseBody。里面所有的方法返回值都直接返回页面
 */
@RestController
@RequestMapping("user")
public class UserController {

    @GetMapping("addUser")
    public String addUser() {
        return "添加用户成功:" + new Date().getTime();
    }

    @GetMapping("deleteUser/{uid}")
    public String deleteUser(@PathVariable(name = "uid") Integer uid) {
        return "删除用户成功:uid=" + uid;
    }

    @GetMapping("updateUser")
    public String updateUser() {
        return "修改用户成功:" + new Date().getTime();
    }

    @GetMapping("findAllUsers")
    public String findAllUsers() {
        return "查询用户成功:" + new Date().getTime();
    }
}

2、浏览访问路径如下,此时未配置用户与角色时,默认用户 admin 登录后,这些方法都可以正常访问。

http://localhost/ssApp/user/addUser
http://localhost/ssApp/user/deleteUser/101
http://localhost/ssApp/user/updateUser
http://localhost/ssApp/user/findAllUsers

3、现在需要实现的需求如下:

1、创建 4 个用户:zhangWuJi(张无忌) 、guoJing(郭靖)、yangGuo(杨过)、weiXiaoBao(韦小宝)

2、创建 4 个人角色:topLevel(顶级) > senior(高级) > middleRank(中级) > primary(初级)

topLevel 角色可以访问 addUser、deleteUser、updateUser、findAllUsers 方法

senior 角色可以访问 deleteUser、updateUser、findAllUsers 方法

middleRank 角色可以访问 updateUser、findAllUsers 方法

primary 角色可以访问 findAllUsers 方法

3、为 zhangWuJi 分配 topLevel 角色,guoJing 分配 senior 角色,yangGuo 分配 middleRank 与 primary 角色,weiXiaoBao 分配 primary 角色

认证与授权

1、自定义类实现 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter,然后重写方法配置认证与授权。

2、@EnableWebSecurity 开启安全认证与授权,详细信息已经在注释中说明。

package com.wmx.www.config;

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;

/**
 * Created by Administrator on 2019/3/28 0028.
 * WebSecurityConfigurerAdapter(抽象类) implements 了 WebSecurityConfigurer<WebSecurity>
 *
 * @EnableWebSecurity :表示开启 Spring Security 安全认证与授权
 */
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 定义用户认证规则
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**inMemoryAuthentication():添加内存用户认证(InMemoryUserDetailsManagerConfigurer),这些账号密码都会存储在内存中,而不是数据库,所以同理还有-
         * jdbcAuthentication():JdbcUserDetailsManagerConfigurer 数据库用户认证
         * passwordEncoder(PasswordEncoder passwordEncoder):密码编码,Spring Security 高版本必须进行密码编码,否则报错
         * UserDetailsBuilder withUser(String username):添加用户
         * UserDetailsBuilder password(String password):为用户添加密码,不能为 null
         * UserDetailsBuilder roles(String... roles):为用户添加角色
         * C and():返回对象,方便链式编程,也可以分开写
         */
        auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder())
                .withUser("zhangWuJi").password("123456").roles("topLevel")
                .and()
                .withUser("guoJing").password("123456").roles("senior")
                .and()
                .withUser("yangGuo").password("123456").roles("middleRank", "primary")
                .and()
                .withUser("weiXiaoBao").password("123456").roles("primary");
    }

    /**
     * 定义请求的授权规则
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * authorizeRequests:表示验证请求
         * antMatchers(String... antPatterns):使用 org.springframework.security.web.util.matcher.AntPathRequestMatcher 的匹配规则
         * permitAll():允许一切用户访问,底层也是调用 access("permitAll")
         * hasRole(String role):url请求允许访问的角色
         * hasAnyRole(String... roles) : url请求允许访问的多个角色
         * access(String attribute):允许访问的角色,permitAll、hasRole、hasAnyRole 底层都是调用 access 方法
         * access("permitAll") 等价于 permitAll()
         */
        http.authorizeRequests().antMatchers("/").permitAll(); // "/":应用首页所以用户都可以访问
        http.authorizeRequests()
                .antMatchers("/user/addUser").hasRole("topLevel") // 首斜杠"/"表示应用上下文,/user/addUser 请求允许 topLevel 角色访问
                .antMatchers("/user/deleteUser/**").hasAnyRole("topLevel", "senior") //"/user/deleteUser/**"允许 "topLevel", "senior" 角色访问,/**匹配任意
                .antMatchers("/user/updateUser").hasAnyRole("topLevel", "senior", "middleRank")//除了这种链式编程,也可以分开写
                .antMatchers("/user/findAllUsers").access("permitAll");

        /**
         * formLogin:指定支持基于表单的身份验证
         * 未使用 FormLoginConfigurer#loginPage(String) 指定登录页时,将自动生成一个登录页面,亲测此页面引用的是联网的 bootstarp 的样式,所以断网时,样式会有点怪
         * 当用户没有登录、没有权限时就会自动跳转到登录页面(默认 /login)
         * 当登录失败时,默认跳转到 /login?error
         * 登录成功时会放行
         */
        http.formLogin();
    }
}

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、此时再次启动应用时:

zhangWuJi 可以访问 addUser、deleteUser、updateUser、findAllUsers 方法

guoJing 可以访问 deleteUser、updateUser、findAllUsers 方法

yangGuo 可以访问 updateUser、findAllUsers 方法

weiXiaoBao  可以访问 findAllUsers 方法

2、这里以 yangGuo 为例进行演示:

Forbidden:不允许的,被禁止的。表示权限不足,这里因为没有配置错误页面,所以直接显示错误信息。

下一篇《 Spring Security 用户注销 与 权限控制

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/88867153