Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手

网页右边,向下滑有目录索引,可以根据标题跳转到你想看的内容
如果右边没有就找找左边
Spring Security
  1. Spring Security是一个高度自定义的安全框架。利用Spring IOC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。
  2. 使用Spring Security的原因:javaEE的Servlet规范或EJB规范中的安全功能缺乏典型企业应用场景。同时认识到他们在WAR或EAR级别无法移植。如果你更换服务器环境,需要花费大量精力重新配置你的应用程序。使用Spring Security解决了这些问题,也提供了很多可定制的安全功能
  3. Spring Security重要核心功能:“认证"和"授权”。
  4. 通俗讲,认证就是你能不能进我家,授权就是,你进我家能干什么,比如我就授权你在我家客厅随意活动,那么其它地方你就不能去,也不能操作
  5. 不通俗讲,认证:是建立一个声明主体的过程(一个主体代表一个用户、设备或一些可以在你程序中执行动作的其它系统),决定这些主体是否可以登录系统。授权:确定一个主体是否允许在你的应用程序中执行一个动作的过程。就是判断用户是否有权限去做某些事
历史
  1. 2003年底,以“The Acegi Security System for Spring”的名字出现,前身为acegi项目
  2. 起因是Spring开发者邮件列表中的一个问题:有人提问是否考虑提供一个基于Spring的安全实现。之后因为时间问题,开发出了一个简单的安全实现,没有深入研究
  3. 几周后,Spring社区中其他成员同样询问安全问题,就将代码开源了出去。
  4. 2004年1月左右,20人左右使用这个项目,随着更多人的加入,2004年3月左右,sourceforge中建立了一个项目acegi,这时并没有认证模块,所有认证功能都是依赖容器完成。而acegi则注重授权。
  5. 之后使用的人越来越多,基于容器实现认证显现不足,acegi中也加入了认证功能。一年后,acegi成为Spring子项目
  6. 2006年5月,acegi 1.0.0版本发布。2007年底acegi更名为Spring Security

一、先写一个简单Spirng Security项目

1. 创建项目,引入依赖
  1. 和普通spring boot项目不同的地方,就是多引入一个security的包
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第1张图片
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.11.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>
2. 编写启动类和controller
  1. 启动类
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第2张图片
  2. controller(简单编写,然后运行项目,复制打印到控制台的密码)
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第3张图片
url访问,查看效果

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第4张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第5张图片

二、自定义认证等逻辑

1. UserDetailsService自定义登录逻辑

  1. 由前面的案例可知,我们什么都没有配置时,账号密码都是Spring Security帮我们生成,实际项目都是查数据库,所以我们需要自定义逻辑,控制认证。
  2. 需要自定义逻辑非常简单,只需要实现UserDetailsService即可
1. 先看看它的源码
  1. UserDetailsService
  1. 可见这个接口,只定义个一个方法,根据方法名,可以判断是根据用户名,加载用户,返回值是UserDetails类型
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第6张图片
  1. UserDetails

它封装了用户的基本信息
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第7张图片
但它是一个接口,想要返回它,必须通过实现类
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第8张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第9张图片

public interface UserDetails extends Serializable {
	Collection<? extends GrantedAuthority> getAuthorities();//获取所有权限
	String getPassword();//获取密码
	String getUsername();//获取用户名
	boolean isAccountNonExpired();//账号是否过期
	boolean isAccountNonLocked();//账号是否被锁定
	boolean isCredentialsNonExpired();//凭证(密码)是否过期
	boolean isEnabled();//是否可用
}
2. 创建实现类,并实现它

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第10张图片

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.ArrayList;
import java.util.List;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    //根据用户名加载用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //1. 模拟从数据库查询用户
        if(!username.equals("admin")){//如果不是admin,那么就表示不是我数据库中的用户,抛出异常或进行逻辑处理
            // 用户不存在的逻辑,我这里直接抛个异常表示一下
            throw new UsernameNotFoundException("用户不存在!!!");
        }
        //2. 模拟,从数据库查询到了用户信息,用户存在的逻辑
        //2.1 封装密码
        String password = "pwd";//将查询到达密码封装
        //2.2 封装权限,假设这个用户查到了两个权限字符,admin1和admin2
        List<String> list = new ArrayList<>();
        list.add("admin1");
        list.add("admin2");
        //2.3 拼接权限
        StringBuilder stringBuilder = new StringBuilder();
        for(int i = 0;i<list.size();i++){
            //拼接成这样 "admin1,admin2"
            if(i==(list.size()-1)){//当权限字符是最后一个,不加逗号
                stringBuilder.append(list.get(i));
            }else{
                stringBuilder.append(list.get(i)+",");
            }
        }
        System.out.println(stringBuilder.toString());
        //2.4 因为权限字符拼接非常麻烦,所以spring security提供了AuthorityUtils工具类,帮我们封装,参数就是权限字符通过逗号分隔,比如"admin1,admin2"
        List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(stringBuilder.toString());
        //3. 返回UserDetails
        UserDetails userDetails = new User(username, password, grantedAuthorities);

        return userDetails;
    }
}
3. 重新运行项目,分析报错
  1. 提示,密码必须是编码加密后的,不能用不编码加密的(其实回头看之前,它提供的密码,就能发现,提供的是编码加密后的密码)
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第11张图片

2. PasswordEncoder密码解析器

  1. Spring Security要求容器中必须有PasswordEncoder实例。所以当自定义登录逻辑时,要求必须给容器注入PasswordEncoder的bean对象
1. 先分析源码
  1. PasswordEncoder接口
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第12张图片
public interface PasswordEncoder {
	//把参数按照特定的解析规则进行解析
	String encode(CharSequence rawPassword);
	//验证从存储中获取的编码后密码,与编码后提交的原始密码是否匹配。匹配返回true,不匹配false
	//第一个参数表示需要被解析的密码,第二个表示存储的密码
	boolean matches(CharSequence rawPassword, String encodedPassword);
	//如果解析的密码能够再次解析且能达到更安全结果,返回true,否则返回false,默认为false
	default boolean upgradeEncoding(String encodedPassword) {
		return false;
	}
}
  1. 同样因为它是接口,我们需要实现类来创建它
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第13张图片
  1. BCryptPasswordEncoder是Spring Security官方推荐的密码解析器,平时多使用这个解析器。
  2. BCryptPasswordEncoder是对bcrypt强散列方法的具体实现。是基于Hash算法实现的单向加密。可以通过strength控制加密强度,默认10。
2. 创建Security配置类,配置解析器Bean实例,然后注入Spring IOC容器,这是自定义登录逻辑的硬性要求

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第14张图片

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig {
    /**
     * 配置密码解析Bean实例
     * 加载到IOC容器
     * 这是Spring Security 自定义登录逻辑的硬性要求
     * @return
     */
    @Bean
    protected PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
3. 修改自定义登录逻辑

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第15张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第16张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第17张图片

//1. 注入PasswordEncoder对象
    @Autowired
    private PasswordEncoder passwordEncoder;


//2. 加密密码
        //2. 模拟,从数据库查询到了用户信息,用户存在的逻辑
        //2.1 封装密码
        String password = "pwd";//将查询到达密码封装
        /**
         * 解析器
         */

        //对密码加密,其实,我们一般在存储用户到数据库的时候,保存密码,直接保存这个加密后的
        String encodePassword = passwordEncoder.encode(password);
        System.out.println(password+"加密后-------------"+encodePassword);

        //判断源字符加密后和内容是否匹配
        boolean matches = passwordEncoder.matches(password, encodePassword);
        System.out.println("原密码和加密后是否匹配-------"+matches);
//3. 返回UserDetails对象时,传入加密后密码
        UserDetails userDetails = new User(username, encodePassword, grantedAuthorities);
重新运行看效果

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第18张图片

3. 连接数据库实现自定义登录逻辑

1. 简单创建一个数据库

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第19张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第20张图片

2. 创建对应实体类

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第21张图片

3. 使用MyBatis 操作数据库
  1. 依赖
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第22张图片
       <!--myBatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
        <!--apace commons工具-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>
  1. mapper接口
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第23张图片
  2. xml映射文件
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第24张图片

DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yzpnb.mapper.TUserMapper">
    <select id="selectByUsername" parameterType="java.lang.String" resultType="com.yzpnb.pojo.TUser">
        select id,username,password from t_user where username=#{username}
    select>
mapper>
  1. 配置文件
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第25张图片
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.47.1:3306/dubbo_demo?serverTimezone=CST&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true #?后面参数表示时区,非常重要
    username: root
    password: 123456
# MyBatis
mybatis:
  # 搜索指定包别名
  type-handlers-package: com.yzpnb.pojo
  # 配置mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath:mybatis/*Mapper.xml
  1. 启动类
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第26张图片
4. 重写自定义登录逻辑

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第27张图片

import com.yzpnb.mapper.TUserMapper;
import com.yzpnb.pojo.TUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private TUserMapper tUserMapper;

    //根据用户名加载用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //1. 从数据库查询用户
        TUser tUser = tUserMapper.selectByUsername(username);

        if(tUser == null){//如果用户不存在
            System.out.println("用户不存在");
            throw new UsernameNotFoundException("用户不存在");
        }
        System.out.println("查询到用户信息------用户名:"+username+"--------密码:"+tUser.getPassword());

        //2 封装权限,假设这个用户查到了两个权限字符,admin1和admin2,嫌麻烦,这里直接封装了
        List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin1,admin2");

        //3. 返回UserDetails,因为数据库中密码就是加密后的,所以直接用就行
        UserDetails userDetails = new User(username, tUser.getPassword(), grantedAuthorities);

        return userDetails;
    }
}

4. 自定义登录页面

用thymeleaf模板简单编写页面
  1. 引入thymeleaf依赖
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第28张图片
  2. 在resources下创建templates文件夹,然后创建login.html页面编写代码作为登录页面
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第29张图片
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <form action="/login" method="post">
        username:<input type="text" name="username"/><br/>
        password:<input type="password" name="password"/><br/>
        <input type="submit"/><br/>
    form>
body>
html>
  1. 再创建一个index.html 作为登录成功后,转到的页面
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第30张图片
编写controller 用来处理一些请求

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第31张图片

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SpringSecurityDemoController {

    @RequestMapping("showLogin")//此注解可以直接跳转页面,一体项目用,但现在前后端分离都用@GetMapping
    public String showLogin(){
        return "login";//可以直接重定向到login.html页面,SpringMVC的知识
    }

    @RequestMapping("loginSuccess")
    public String loginSuccess(){
        return "index";
    }
}

1. 重点(Spring Security最核心地方)配置类修改

  1. 配置类中,设置登录页面。需要继承WebSecurityConfigurerAdapter,并重写configure方法,常用设置如下
  1. successForwardUrl():登录成功后跳转地址
  2. loginPage():登录页面
  3. loginProcessingUrl():登录页面表单提交地址,此地址可以不真实存在
  4. antMatchers():匹配内容
  5. permitAll():允许
  6. authorizeRequests():授权相关的
  7. formLogin():所有和表单有关系的操作
1. 先看看源码

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第32张图片

	// @formatter:off
	protected void configure(HttpSecurity http) throws Exception {
		logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");

		http
			.authorizeRequests()//授权相关的
				.anyRequest().authenticated()
				.and()
			.formLogin().and()//所有和表单有关系的操作
			.httpBasic();
	}
2. 修改我们先前写过的配置类

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第33张图片

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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 配置密码解析Bean实例
     * 加载到IOC容器
     * 这是Spring Security 自定义登录逻辑的硬性要求
     * @return
     */
    @Bean
    protected PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置登录页面,注意请求,要和controller中一致
        http.formLogin()
                .loginPage("/showLogin")//只要你没认证的情况下请求服务器当前应用程序的端口,都会到这个页面,如果请求这个页面,会跳转到登录页面(这个逻辑在controller层中编写)
                //当url中有/login,那么就会执行我们的自定义登录逻辑,就是我们上面配置的
                .loginProcessingUrl("/login")//这里还指定登录成功后地址栏中显示的地址,如果请求上面的页面,就跳转到登录页面(这个是controller层控制的),但是地址栏显示的,是这里设置的地址,
                .successForwardUrl("/loginSuccess");//登录成功返回的页面,就是地址栏虽然是上面设置的/login,但是实际登录成功后,访问的请求是这个

        //配置授权
        http.authorizeRequests()
                //只要请求showLogin页面,就全部放行
                .antMatchers("/showLogin").permitAll()//antMatchers,表示指定一个页面,permitAll表示不需要授权,全部放行
                .anyRequest().authenticated();//除了上面配置的,其它任何请求(anyRequest),都必须已经通过验证(authenticated)才能放行

        http.csrf().disable();//让csrf禁用,否则会一直验证,进入死循环,这个后面会专门讲
    }
}
3. 运行查看效果
  1. 访问showLogin,会直接放行,然后进入controller,在里面直接重定向到了登录页面
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第34张图片
  2. 登录成功,地址栏会显示我们设定URL,同时请求/login,那么检测到url中有login,就会执行我们自定义登录逻辑,然后重定向到/loginSuccess,这个请求里面重定向了index.html页面
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第35张图片

2. 登录失败页面

  1. 我们上面如果登录失败,依然会在登录页面,现在我们想实现,登录失败,进入错误页面
1. 创建一个页面,作为登录失败页面

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第36张图片

2. 编写controller

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第37张图片

3. 配置类

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第38张图片

//配置登录页面
        http.formLogin()
                .loginPage("/showLogin")//如果请求这个页面,跳转到登录页面,并且,只要你没认证的情况下请求服务器当前应用程序的端口,都会到这个页面
                .loginProcessingUrl("/login")
                .successForwardUrl("/loginSuccess")//登录成功返回的页面
                .failureForwardUrl("/loginFail")//登录失败跳转的页面
                ;
4. 重新运行测试

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第39张图片

3. 自定义登录参数

  1. 前面我们讲,必须用username和password两个参数,那么也可以通过参数设置
1. 登录页面将参数名字改了

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第40张图片

2. 设定参数

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第41张图片

        //配置登录页面
        http.formLogin()
                .loginPage("/showLogin")//如果请求这个页面,跳转到登录页面,并且,只要你没认证的情况下请求服务器当前应用程序的端口,都会到这个页面
                .loginProcessingUrl("/login")//如果请求上面的页面,就跳转到登录页面(这个是controller层控制的),这里指定登录页面,就是登录成功后url中的地址
                .successForwardUrl("/loginSuccess")//登录成功返回的页面
                .failureForwardUrl("/loginFail")//登录失败跳转的页面
                .usernameParameter("un")//配置username的参数名
                .passwordParameter("pwd")//配置password的参数名
                ;

4. 解决重复提交表单问题,并且可以站外转发(前后端分离项目使用)

  1. 当我们登录成功进入页面,刷新时,会提示重新提交表单,接下来解决这个问题
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第42张图片
1. 问题分析
  1. 首先,页面跳转,会重发请求,但是重定向不会,所以我们当前使用的都是跳转,我们需要改成重定向
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第43张图片
.successHandler(new AuthenticationSuccessHandler() {
					//重写了方法,主要功能就是重定向,源码讲解在下面
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.sendRedirect("/loginSuccess");
                    }
                })
2. 源码

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第44张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第45张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第46张图片

重新运行看效果

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第47张图片

2. 那么失败页面呢,设置完全一样,但是需要授权

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第48张图片

.failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                        httpServletResponse.sendRedirect("/loginFail");
                    }
                })

//配置授权,失败页面"/loginFail"也得授权
        http.authorizeRequests()
                //只要请求showLogin页面,就全部放行
                .antMatchers("/showLogin","/loginFail").permitAll()//antMatchers,表示指定一个页面,permitAll表示不需要授权,全部放行
                .anyRequest().authenticated();//除了上面配置的,其它任何请求(anyRequest),都必须已经通过验证(authenticated)才能放行
那么如何站外跳转呢?毕竟现在都是前后端分离项目,页面不是和你项目写在一起的

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第49张图片

.successHandler(new AuthenticationSuccessHandler() {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        //获取User对象
        User user = (User) authentication.getPrincipal();
        System.out.println(user.getUsername());//用户名
        System.out.println(user.getPassword());//密码,为了安全考虑,这里不允许打印密码,会自动打印null
        System.out.println(user.getAuthorities());//权限
        httpServletResponse.sendRedirect("http://www.baidu.com");
    }
})

5. 介绍一些和url,静态资源有关的东西,不常用就不详细介绍了

  1. public C antMatchers(String… antPatterns):前面我们的授权配置方法
  1. 可见参数是不定长参数,用于匹配URL规则,如下:
  1. ?:匹配一个字符
  2. *:匹配0个或多个字符
  3. **:匹配0个或多个目录
  1. 实际项目中,需要放行所有静态资源时,就可以这样写,比如放行js文件夹下所有js脚本
//js文件夹下所有文件放行
.antMatchers("/js/**").permitAll()
//所有js后缀文件都放行
.antMatchers("/**/*.js").permitAll()

6. 异常403处理方案

  1. 使用Spring Security 时经常会看见403(无权限),默认情况下显示效果如下
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第50张图片
  2. 而实际项目中可以都是一个异步请求,显示上述效果对用户很不友好(比如整个系统,你只有一个菜单没有权限进去,这时你不小心点了一些,直接跳出一个403页面,感觉是很不好的,一般都是弹出一个对话框,提示一下没有权限),Spring Security支持自定义权限受限
1. 设置一个拒绝一切用户访问的url,以实现403页面的出现

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第51张图片

.antMatchers("abc").denyAll()//拒绝访问abc的一切请求
2. 写一个组件,专门用来处理403

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第52张图片

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        //异步响应,需要处理乱码
        httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);//响应状态设置为禁止,否则返回的状态码是200,成功,不符合业务要求
        httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");//设置响应编码

        PrintWriter out = httpServletResponse.getWriter();//设置响应的流
        out.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员!\"}");//将数据输出到页面
        out.flush();//刷新流
        out.close();//关闭流
    }
}
3. 配置类中配置
  1. 先引入组件
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第53张图片
  2. 配置异常处理
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第54张图片
        //配置异常处理
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);//配置,拒绝访问处理程序为我们刚才编写的组件
  1. 另外,同步的话,就是不前后端分离,也可以写一个controller来处理,但现在基本没用
        //配置异常处理
        http.exceptionHandling()
                .accessDeniedPage("/showException");//跳转到指定请求处理

三、自定义授权、访问控制等逻辑

1. 利用角色的权限,实现限制url

  1. Spring Security提供了很多权限控制,比如一个用户登录后,必须具备admin1权限,才可访问/successLogin页面,如果它只有admin2权限,那么就无法访问
  2. 用户权限是在自定义登录逻辑中,创建User对象时指定的,权限字符严格区分大小写
    在这里插入图片描述
1. 配置url访问权限的常用方法(在配置类中配置)
  1. hasAuthority(String):必须具备指定权限,才可访问
//访问/loginSuccess这个url必须具有admin1权限
.antMatchers("/loginSuccess").hasAuthority("admin1")
  1. hasAnyAuthority(String…):具备给定权限中的某一个,就可以访问
//访问/loginSuccess这个url必须具有admin1或admin2其中一个权限
.antMatchers("/loginSuccess").hasAnyAuthority("admin1","admin2")
  1. hasRole(String):具备给定角色就可以访问,否则出现403
  1. 给用户赋予角色,也是创建User对象时指定,和权限放在一起即可
  2. 赋予角色时,需要以ROLE_开头,后面添加角色名,例如ROLE_manager,其中manager是角色名,ROLE_是固定的前缀。(因为和权限放在一起,程序分不清谁是权限,谁是角色,所以角色加个前缀,方便区分)
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第55张图片
  3. 但是使用hasRole()这个方法时,参数直接传manager,前缀ROLE_不需要指定,否则报错
//访问/loginSuccess这个url必须具有manager角色
.antMatchers("/loginSuccess").hasRole("manager")
  1. hasAnyRole(String…):具备给定角色中的某一个,就可以访问
  2. haslpAddress(String):请求的是指定ip,就可以访问
  1. 可以通过request.getRemoteAddr()获取ip
  2. 注意:本机测试时,localhost和127.0.0.1输出ip地址不一样
  3. 当浏览器通过localhost进行访问时,控制台打印内容是getRemoteAddr:0:0:0:0:0:0:0:1
  4. 当浏览器通过127.0.0.1访问时控制台打印内容时:getRemoteAddr:127.0.0.1
  5. 如果是普通ip192.168.xxx.xxx之类的,都会原样输出:getRemoteAddr:192.168.xxx.xxx
2. 设置访问/loginSuccess这个url必须具有admin1权限,访问/abc必须具有admin3
  1. 封装权限
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第56张图片
  2. 配置
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第57张图片
3. 设置访问/loginSuccess这个url必须具有manager角色,访问/abc必须具有abc角色
  1. 配置类
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第58张图片
4. 设置访问/loginSuccess这个url必须使用127.0.0.1ip,访问/abc必须使用ip192.168.0.1

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第59张图片

2. 连接数据库实现权限认证

1. rbac表设计

我们需要两个用户来测试

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第60张图片

创建角色表

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第61张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第62张图片

创建用户与角色的对应关系表

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第63张图片
在这里插入图片描述

创建菜单表
  1. 这个表可能有些难理解,结合想要实现的场景来分析一些
  1. 首先一个系统,有很多菜单,比如用户管理,用户管理下有很多子菜单,比如学生管理,讲师管理
  2. 那么如何确定父子关系呢,这里就是采用码表的方式,通过父id来确定自己的父亲
  3. 顶级菜单父id为0,它的子菜单的父id就是这个顶级菜单的id,依次类推,除了顶级菜单父id为0外,其它菜单项的父id都会记录自己父菜单的id
  4. 除了菜单还有很多按钮,比如学生管理菜单下,有新增,删除按钮,那么必须在数据库指定这些菜单的类型,所以我们通过一些特定字符来表示一个菜单的类型,比如menu就是菜单,button就是按钮,或者分的更细,student就是操作学生的按钮
  5. 每个菜单都应该具备自己的权限,只有用户拥有相应权限,才能操作菜单,所以数据库中应该有一个权限字段,保存菜单权限
  6. 额外的,我们想实现,用户进入系统,只能看到自己有权限操作的菜单,比如一个普通用户,只能查看菜单,不能使用增删改查之类的操作按钮
  7. 那么我们就应该建立一个关系表,决定一个角色能够操作哪些菜单

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第64张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第65张图片

角色和菜单的关系表

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第66张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第67张图片

2. mapper代码,实现对rbac表的数据库操作

为了省事,就不给每张表建立实体类了,直接用List
mapper接口

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第68张图片

xml映射文件
  1. sql语句测试
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第69张图片
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第70张图片
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第71张图片
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第72张图片
  1. xml文件编写
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第73张图片

DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yzpnb.mapper.TUserMapper">
    <select id="selectByUsername" parameterType="java.lang.String" resultType="com.yzpnb.pojo.TUser">
        select id,username,password from t_user where username=#{username}
    select>
    <select id="selectRoleById" parameterType="java.lang.Integer" resultType="java.lang.String">
        select
            name
        from
            t_user_role as tur
                left join
            t_role as r
            on
                tur.rid = r.id
        where
            tur.uid = #{userId}
    select>
    <select id="selectPermissionsByUserId" parameterType="java.lang.Integer" resultType="java.lang.String">
        select
            m.permission as permission
        from
            t_user_role as tur
                left join
            t_role as r
            on
                tur.rid = r.id
                left join
            t_role_menu as trm
            on
                r.id = trm.rid
                left join
            t_menu as m
            on
                m.id = trm.mid
        where
            tur.uid = #{userId}
    select>
mapper>

3. 重写登录授权逻辑代码和配置类,测试

登录逻辑

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第74张图片

        //2 封装权限和角色
        List<String> roles = tUserMapper.selectRoleById(tUser.getId());//获取用户角色
        List<String> permissions = tUserMapper.selectPermissionsByUserId(tUser.getId());//获取用户权限

        StringBuilder stringBuilder = new StringBuilder();

        //拼接权限字符串
        for(int i = 0;i<roles.size();i++){
            if(i == roles.size()-1)  {//当拼接最后一角色字符时判断
                //如果没有权限字符,那么末尾不加逗号,如果有权限字符,末尾加逗号
                if(permissions.size()>0) stringBuilder.append("ROLE_"+roles.get(i)+",");
                else stringBuilder.append("ROLE_"+roles.get(i));
            }else 
                stringBuilder.append("ROLE_"+roles.get(i)+",");

        }
        for (int i = 0;i<permissions.size();i++){
            if(i == permissions.size()-1) stringBuilder.append(permissions.get(i));
            else stringBuilder.append(permissions.get(i)+",");
        }

        List<GrantedAuthority> grantedAuthorities =
                AuthorityUtils.commaSeparatedStringToAuthorityList(stringBuilder.toString());

        System.out.println("用户的权限字符为:"+stringBuilder);
配置类

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第75张图片

.antMatchers("/loginSuccess").hasRole("管理员")
.antMatchers("/abc").hasAuthority("demo:insert")

3. 基于表达式的访问控制

  1. 之前学习的登录用户权限判断实际上底层都是调用access(表达式),例如hasRole,hasAnyRole等,底层都是调用access()方法,
  2. 因为实际项目中,很可能出现Spring Security提供的方法实现不了的需求,这时就要我们通过这个方法,自定义访问控制方法
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第76张图片
1. 建立service接口编写实现类
  1. 接口
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第77张图片
  2. 实现类,实现判断权限列表中是否包含角色管理员,如果有返回true,没有返回false,记住通过@Service注解,将其注入到容器中
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第78张图片
import com.yzpnb.service.MyAccessService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;

@Service
public class MyAccessServiceImpl implements MyAccessService {
    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        //当我们自定义登录逻辑UserDetails对象注入时,通过这个方法可以获取到
        Object o = authentication.getPrincipal();

        if(o instanceof UserDetails){//如果获取到的确实是UserDetails对象,那么获取UserDetails对象
            UserDetails userDetails = (UserDetails) o;

            Collection<? extends GrantedAuthority> collection = userDetails.getAuthorities();//获取权限列表

            /**实现判断权限列表中,是否有管理员角色**/
            //contains方法,用于判断,Collection接口列表中,有没有指定元素
            //因为Collection列表中元素是GrantedAuthority类型的,所以需要new SimpleGrantedAuthority("ROLE_管理员")
            //将一个字符串"ROLE_管理员"转换为GrantedAuthority类型的对象
            return collection.contains(new SimpleGrantedAuthority("ROLE_管理员"));
        }

        return false;
    }
}
使用自定义访问控制
  1. 我们前面讲过,access()方法可以通过表达式控制
  2. 那么在@Service注解没有参数的情况下,我们刚才的接口匹配的表达式就是

“@myAccessServiceImpl.hasPermission(request,authentication)”

  1. 接下来看怎么具体使用
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第79张图片
 .antMatchers("/loginSuccess").access("@myAccessServiceImpl.hasPermission(request,authentication)")

4. 基于注解的访问控制

  1. 虽然提供了一些访问控制注解,但默认是不可用的,需要通过在启动类添加@EnableGlobalMethodSecurity()注解开启后,才能使用,注意,每个注解,都需要单独开启,而且不能共存
  2. 这些注解可以写到Service接口或方法上,也可以写到Controller或Controller中的方法上,一般写在Controller的方法上,当客户端请求Controller某一方法,就会进行访问控制
  3. 效果就是,条件运行,程序正常执行,条件不允许,会报错500
1. 常用注解介绍
  1. @Secured:判断是否具有直接角色,参数要以ROLE_开头,可以写在方法或类上
  2. @PreAuthorize:访问方法或类之前先判断权限,使用较多,参数就和配置类中使用方法一样
  3. @PostAuthorize:方法或类执行结束后判断权限,此注解很少使用,不做讲解
@Secured注解效果
  1. 先放行请求
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第80张图片
  2. 启动类开启注解访问控制功能
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第81张图片
@EnableGlobalMethodSecurity(securedEnabled = true)
  1. 测试@Secured(“ROLE_管理员”)
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第82张图片
@PreAuthorize注解效果
  1. 开启注解
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第83张图片
  2. 测试
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第84张图片

5. Remember Me 记住我功能

  1. 用户只需要在登录时添加remember-me复选框,取值为true,那么框架会自动把用户信息存储到数据源中,以后就可以不重复登录访问
  2. 需要添加额外依赖,底层依赖Spring-JDBC,但是实际开发中多使用MyBatis框架,而很少直接导入spring-jdbc,所以我们只需要mybatis启动器(这些依赖我们前面都已经加过了)
1. 编写配置类,并注入Bean对象,这里涉及到了自动建表,第一次需要建立,第二次就不需要了,所以我们自动建表一般都手动建立,如果使用自动建立,那么第二次运行需要注释掉自动建表代码
  1. 配置类
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第85张图片
package com.yzpnb.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
public class RememberMeConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    protected PersistentTokenRepository getPersistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动建表,第二次启动需要注释掉
        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
}
2. 编写配置类
  1. spring security 配置类,将登录逻辑和刚刚配置的bean实例注入,配置好,再配置令牌失效时间为120秒
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第86张图片
    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

//配置remember Me
        http.rememberMe()
                .tokenValiditySeconds(120)//有效时间,单位秒,超过120秒令牌失效,需要重新登录
                .userDetailsService(userDetailsService)//登录逻辑交给哪个对象
                .tokenRepository(persistentTokenRepository);//持久层对象,就是刚配置的自动建表的对象
3. 重写登录页面,添加Remember me 复选框

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第87张图片

remember-me:<input type="checkbox" name="remember-me" value="true"/>
测试运行,并注释掉自动建表代码
  1. 运行后,注释自动建表代码
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第88张图片
  2. 查看效果(数据库令牌添加成功后,无论重启项目多少次,都无需重复登录,只有超过有效时间后才需要重新登录)
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第89张图片
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第90张图片

四、退出登录

  1. 用户只需要发送/logout请求即可,spring security默认退出登录请求为/logout,退出成功后跳转到/login?logout
  2. 实现非常简单,在页面中添加/logout超链接即可
<a href="/logout"/>退出登录
  1. 但是通常我们为了实现更好的退出效果,会添加退出配置,
1. 页面中添加退出超链接

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第91张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第92张图片
Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第93张图片

2. 配置类配置方法

Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第94张图片

       //配置退出登录
        http.logout()
                .logoutUrl("/logout")//设置退出登录,访问url,这里设置什么,我们请求退出时,就需要请求什么
//                .logoutSuccessUrl("/showLogin")//退出成功后跳转
                .logoutSuccessHandler(new LogoutSuccessHandler() {//退出成功后重定向方法
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.sendRedirect("/showLogin");
                    }
                });

五、Spring Security中的CSRF

  1. 还记得自定义登录配置时的csrf代码吗?没有内一行代码会导致用户无法被认证
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第95张图片
  2. 这行代码的含义是,关闭csrf防护
http.csrf().disable();
CSRF
  1. 跨站请求伪造,也称One Click Attack或者Session Riding。通过伪造用户请求访问受信任站点的非法请求访问。
  2. 跨域:只要网络协议,ip地址,端口中任何一个不相同就是跨域请求
  3. 客户端与服务器进行交互时,由于http协议本身是无状态协议,所以引入cookie进行记录客户端身份。在cookie中会存放session id用来识别客户端身份。
  4. 跨域情况下,session id可能会被第三方恶意劫持,通过这个session id向服务端发起请求时,服务端会认为这个请求合法,可能会被黑客利用
Spring Security中的CSRF
  1. Spring Security4开始CSRF防护默认开启,默认拦截请求,进行CSRF处理。CSRF为了保证不是其它第三方网站访问,要求访问时携带参数名为_csrf,值为token(token在服务端产生)的内容,如果token和服务端保存的token不一致,那么拒绝访问。
  2. 所以如果你想使用CSRF的保护,那么你每次发送请求,只要发送一个参数名为_csrf的参数即可,至于参数值,是一个token字符串,需要服务器去生成,返回给你
    Spring Security + OAuth2 + JWT学习笔记,超简单且详细的讲解,完全手敲代码,看完直接上手_第96张图片

六、Oauth2 、SpringSecurityOauth2

由于篇幅原因,我将其放在这篇文章中https://blog.csdn.net/grd_java/article/details/121902912

七、前后端分离,实现登录,权限管理系统

因为篇幅原因,我将其放在这篇文章中https://blog.csdn.net/grd_java/article/details/121925792

你可能感兴趣的:(java框架,spring,Security,csrf,权限认证框架)