怀旧网,博客详情:Spring Security 介绍

1、Mybatis 详细介绍

2、Spring 详细介绍

3、SpringMVC 详细介绍

4、Vue 使用详细介绍

5、Spring Boot 介绍

6、Spring Boot 配置文件讲解

7、Spring Security 介绍

8、Shiro 介绍

9、Spring Boot 整合 Swagger

10、Spring Boot 任务

11、Redis 详解介绍

12、Docker 使用详细介绍

13、JVM 介绍

14、JUC并发编程

原创

Spring Security 介绍

简介

​ Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。

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

  • 用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

​ 对于上面提到的两种应用情景,Spring Security 框架都有很好的支持。在用户认证方面,Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等。在用户授权方面,Spring Security 提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制。

认识SpringSecurity

Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理! 记住几个类:

WebSecurityConfigurerAdapter:自定义Security策略 AuthenticationManagerBuilder:自定义认证策略 @EnableWebSecurity:开启WebSecurity模式 Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。 “认证”(Authentication) 身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。 身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。 “授权” (Authorization) 授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。 这个概念是通用的,而不是只在Spring Security 中存在。

实战使用

1、创建一个SpringBoot项目

导入需要的pom依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity6</artifactId>
    </dependency>

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

修改配置文件:

后缀改为yml格式:

server:
  port: 80
spring:
  thymeleaf:
    cache: false

创建一个Controller:

image-20240506113146383

@Controller
public class TestController {
    @RequestMapping({"/", "/index"})
    public String index(){
        return "index";
    }
}

前端index.html

image-20240506113215771

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>测试界面</title>
    </head>
    <body>
        <h1>这里是首页、</h1>
    </body>
</html>

启动项目:

image-20240506113109737

控制台会默认生成一个密码:访问:http://localhost/login

出现如下界面:

image-20240506105122085

这个界面因为会访问外网的一个css所以会加载很慢,我们去项目里面添加配置:

2、自定义配置登录界面

自定义编写一个登录界面:

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>登录</title>
    </head>
    <body>
        <div style="font-size: 20px;">
            <form th:action="@{/login}" method="post">
                用户名:<input type="text" name="username" /><br />
                密码:<input type="password" name="password" /><br />
                <input type="submit" value="登录" />
            </form>
        </div>
    </body>
</html>

编写一个controlle跳转到login界面

@GetMapping("/login")
public String login(){
    return "login";
}

重庆后访问:http://localhost/

还是默认访问到security自带的登录界面:

现在就需要我们去配置默认的请求地址了

创建一个配置文件类:

SecurityConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;


@Configuration
@EnableWebSecurity // 可以省略,在底层自动帮我们配置了这个注解
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 配置基本的拦截器
        http.authorizeHttpRequests(authorize -> {
            authorize.requestMatchers("/login").permitAll() // 放行登录界面
                .anyRequest() // 对所有请求开启授权保护
                .authenticated() // 已认证的请求会被自动授权

            ;
        });

        http.formLogin(login -> {
            login.loginPage("/login") // 自定义登录地址
                .successForwardUrl("/") // 登录成功,自动跳转到首页
            ;
        });

        return http.build();
    }
}

再次访问:

image-20240506154055680

自动跳转到登录界面:

现在输入用户名和密码:

用户名为:user (默认的)

密码为:控制台自动输出的密码:

image-20240506154150052

image-20240506154430469

登录成功,返回到首页

3、自定义配置登录用户名和密码

只需要在配置文件中加入一下配置:

server:
  port: 80
spring:
  thymeleaf:
    cache: false
  security:
    user:
      name: huaijiu
      password: 123

重启,再次登录:

image-20240506154657668

登录成功!

image-20240506154703515

4、配置页面的访问权限

1.首先导入需要的静态资源: 链接:网页链接 提取码:clsq

image-20240506114209372

1、将下载的配置导入到项目中:

image-20240506154727497

2、重启项目测试一下:访问界面:http://localhost/ 并登录用户

image-20240506154830855

image-20240506154902682

登录成功,进入首页!

访问首页的level界面:

image-20240506154939052

报错404,原因没有配置对应的controlle

3、添加对应映射路径

添加映射:

@RequestMapping("/level1/{id}")
public String level1(@PathVariable("id") String id){
    return "views/level1/" + id;
}

@RequestMapping("/level2/{id}")
public String level2(@PathVariable("id") String id){
    return "views/level2/" + id;
}

@RequestMapping("/level3/{id}")
public String level3(@PathVariable("id") String id){
    return "views/level3/" + id;
}

添加完成-重启项目进行访问:

image-20240506160057565

这里的可以随意进行访问

image-20240506160113065image-20240506160118203

3、添加配置文件内容

配置需要拥有对应权限才可以访问对应资源

// 配置基本的拦截器
http.authorizeHttpRequests(authorize -> {
    authorize.requestMatchers("/login").permitAll() // 放行登录界面
        .requestMatchers("/level1/**").hasAnyRole("vip1") // 配置对应请求,需要对应权限才可以访问
        .requestMatchers("/level2/**").hasAnyRole("vip2")
        .requestMatchers("/level3/**").hasAnyRole("vip3")
        .anyRequest() // 对所有请求开启授权保护
        .authenticated() // 已认证的请求会被自动授权
        ;
});

重启项目,访问测试:

image-20240506160350309

报错:403 没有访问权限

5、配置用户认证

1、基于内存的用户认证

添加配置文件:

@Bean
public UserDetailsService userDetailsService(){
    // 1.使用内存数据进行认证
    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
    // 2.创建三个用户
    UserDetails user1 = User.withDefaultPasswordEncoder().username("h1").password("123").roles("vip1").build();
    UserDetails user2 = User.withDefaultPasswordEncoder().username("h2").password("123").roles("vip2", "vip3").build();
    UserDetails user3 = User.withDefaultPasswordEncoder().username("h3").password("123").roles("vip1", "vip2", "vip3").build();
    // 3.将这三个用户添加到内存中
    manager.createUser(user1);
    manager.createUser(user2);
    manager.createUser(user3);

    return manager;
}

登录用户h1

image-20240506200057915

访问:http://localhost/level1/1

image-20240506200110382

访问成功:因为登录的hj1用户vip的权限,可以访问level1下的所有资源 测试访问其他界面:

image-20240506201830436

报错!原因:没有对应访问权限!

2、基于数据库的用户认证

模拟Dao层,查询用户数据:

编写User实体类: MyUser.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyUser {
    private String username; // 用户名
    private String password; // 密码
    private String[] rol; // 权限
}

创建Dao: MyUserDao.java

public class MyUserDao {
    public static List<MyUser> userList;

    static {
        userList = new ArrayList<>();

        userList.add(new MyUser("h1", "123", new String[]{"vip1"}));
        userList.add(new MyUser("h2", "123", new String[]{"vip2", "vip3"}));
        userList.add(new MyUser("h3", "123", new String[]{"vip1", "vip2", "vip3"}));
    }

    public static List<MyUser> getList(){
        return userList;
    }

    public static MyUser getUserByName(String name){
        for (MyUser myUser : userList) {
            if(myUser.getUsername().equals(name)){
                return myUser;
            }
        }

        return null;
    }
}

创建一个DBUserDetailsManager.java类 实现 UserDetailsManager 和 UserDetailsPasswordService 两个接口

image-20240508095753397

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    MyUser user = MyUserDao.getUserByName(username);

    if(user == null){
        throw new UsernameNotFoundException(username);
    }

    // 创建权限列表
    Collection<GrantedAuthority> authorities = new ArrayList<>();
    for (String s : user.getRol()) {
        authorities.add(() -> s);
    }

    return new User(user.getUsername(), // 用户名
                    new BCryptPasswordEncoder().encode(user.getPassword()), // 密码
                    true, // 是否启用
                    true, // 账号是否过期
                    true, // 用户凭证是否过期
                    true, // 用户是否未被锁定
                    authorities // 用户的权限列表

                   );
}

修改配置文件:

@Bean
public UserDetailsService userDetailsService(){
    DBUserDetailsManager manager = new DBUserDetailsManager();

    return manager;
}

修改配置认证代码:

// 配置基本的拦截器
http.authorizeHttpRequests(authorize -> {
    authorize.requestMatchers("/login").permitAll() // 放行登录界面
        .requestMatchers("/level1/**").hasAnyAuthority("vip1") // 配置对应请求,需要对应权限才可以访问
        .requestMatchers("/level2/**").hasAnyAuthority("vip2")
        .requestMatchers("/level3/**").hasAnyAuthority("vip3")
        .anyRequest() // 对所有请求开启授权保护
        .authenticated() // 已认证的请求会被自动授权
        ;
});

重启运行项目:

image-20240508100645599

登录h1的用户,访问vip1资源

image-20240508100704651

访问成功!

测试vip2权限

image-20240508100720000

报错,没权限

6、基于方法的认证授权

注销掉基于配置是授权代码:

image-20240508101012093

开启方法授权的配置,在配置类最上面添加注解:@EnableMethodSecurity

image-20240508101439063

​ 给方法添加授权注解:@PreAuthorize("hasAuthority('vip1')")

@RequestMapping("/level1/{id}")
@PreAuthorize("hasAuthority('vip1')")
public String level1(@PathVariable("id") String id){
    return "views/level1/" + id;
}

@RequestMapping("/level2/{id}")
@PreAuthorize("hasAuthority('vip2')")
public String level2(@PathVariable("id") String id){
    return "views/level2/" + id;
}

@RequestMapping("/level3/{id}")
@PreAuthorize("hasAuthority('vip3')")
public String level3(@PathVariable("id") String id){
    return "views/level3/" + id;
}

使用注解后即可完成配置!

其他操作

1、记住我功能

添加支持记住我功能配置

// 开启记住我配置:
http.rememberMe(remember -> {
    remember.tokenValiditySeconds(60 * 60 * 24 * 7) // 有效时间:单位s 默认为14天
        .rememberMeParameter("jizhuwo") // 前端提交name的名称对应
        .rememberMeCookieName("jizhuwo") // cookies记录中的名字
        ;
});

编写前端登录界面:添加选项 (和上面的配置对应-要是上面的配置没编写,可以使用默认的remember-me)

 <input type="checkbox" name="jizhuwo" value="true" />记住我<br /> 

image-20240508104239198

2、注销功能

添加配置文件

// 注销的配置
http.logout(logout -> {
    logout.logoutUrl("/logout") // 注销的请求地址
        .invalidateHttpSession(true) // 清除session信息,默认true
        .clearAuthentication(true) // 清除认证信息,默认true
        .logoutSuccessUrl("/login").permitAll(); // 注销成功后,跳转的位置
});

//关闭跨域访问,解决注销404问题
http.csrf(csrf -> {
    csrf.disable();
});

修改添加注销按钮:(首页--index.html界面)

<!--登录注销-->
<div class="right menu">
    <a class="item" th:href="@{/logout}">
        <i class="address card icon"></i> 注销
    </a>
</div>

image-20240508104622267

点击注销即可完成注销!

3、整合thymeleaf 实现有权限才可以查看对应菜单

在前端index界面导入 命名空间

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6"

image-20240508110559436

在每个请求位置添加如下配置:

sec:authorize="hasRole('vip1')"

image-20240508110829872

配置完成启动项目:登录用户h1

image-20240508110850929

登录用户h2:

image-20240508110923429

达成效果:

添加判断,如果用户登录就显示用户的用户名:

直接添加代码:

<!--如果已登录-->
<div class="right menu" sec:authorize="isAuthenticated()"> <!-- 判断是够已经登录 -->
    <a class="item">
        <i class="address card icon"></i>
        用户名:<span sec:authentication="principal.username"></span>
    </a>
</div>

image-20240508111215989

  • 平台作者:怀旧(联系作者)
  • QQ:444915368
  • 邮箱:444915368@qq.com
  • 电话:17623747368
  • 评论

    登录后才可以进行评论哦!

    回到顶部 留言