spring security技术分享(一)

本文涉及的产品
访问控制,不限时长
简介: 用户认证就是判断一个用户的身份是否合法的过程,用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。认证是确认某主体在某系统中是否合法、可用的过程。这里的主体既可以是登录系统的用户,也可以是接入的设备或者其他系统。

一、初识认证和授权



1.1 认证


1、什么是认证?


输入账号和密码 登录微信的过程就是认证。


2、为什么要认证?


认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源。


3、认证的定义?


用户认证就是判断一个用户的身份是否合法的过程,用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。

认证是确认某主体在某系统中是否合法、可用的过程。这里的主体既可以是登录系统的用户,也可以是接入的设备或者其他系统。


4、常见的用户身份认证方式都有哪些?


用户名密码登录,二维码登录,手机短信登录,指纹认证等方式。


1.2 会话


用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保证在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制,常见的有基于session方式、基于token方式等。


基于session的认证方式如下图:


1.png


它的交互流程是,用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话)中,发给客户端的 session_id存放至cookie中,这样用户客户端请求时带上session_id就可以验证服务器端是否存在session数据,以此完成用户的合法校验,当用户退出系统或session过期销毁时,客户端的session_id也就无效了。


基于token方式如下图:


2.png


它的交互流程是,用户认证成功后,服务端生成一个token发给客户端,客户端可以放到cookie或localstorage等存储中,每次请求时带上token,服务端收到token通过验证后即可确认用户身份。


基于session的认证方式由Servlet规范定制,服务端要存储session信息需要占用内存资源,客户端需要支持 cookie 。

基于token的方式则一般不需要服务端存储token ,并且不限制客户端的存储方式。

如今移动互联网时代更多类型的客户端需要接入系统,系统多是采用前后端分离的架构进行实现,所以基于token的方式更适合。


1.3 授权


1、什么是授权?


微信群主解散微信群,这个根据用户的权限来控制用户使用资源的过程就是授权。


2、为什么要授权?


认证是为了保证用户身份的合法性,授权则是为了更细粒度的对隐私数据进行划分,授权是在认证通过后发生的,控制不同的用户能够访问不同的资源。


3、授权的定义?


授权是用户认证通过根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则正常访问,没有权限则拒绝访问。

授权是指当主体通过认证之后,是否允许其执行某项操作的过程。


1.4 授权的数据模型


一句话可以总结授权的数据模型:主体对资源进行权限操作。

这里的主体既可以是登录系统的用户,也可以是接入的设备或者其他系统。


3.png


1.5 RBAC


1.5.1 角色访问控制


RBAC基于角色的访问控制(Role-Based Access Control),是按角色进行授权。

举个例子,部长可以分配任务:


if(user.hasRole("部长角色id")){
  分配任务;
}


若此时分配任务的角色产生变化,变为部长和产品经理,那么就要修改代码,如下:

if(user.hasRole("部长角色id")||user.hasRole("产品经理角色id")){
  分配任务;
}


由此可见,当根据角色进行授权时,需要修改代码,系统的可扩展性差。


1.5.2 资源访问控制


RBAC基于资源的访问控制(Resource-Based Access Control),是按资源(或权限)进行授权。


举个例子:用户必须具有分配任务权限才可以给员工分配任务:


if(user.hasPermission("分配任务权限标识")){
  分配任务;
}


由此可见,只要系统设计时定义好分配任务的权限标识,即使分配任务所需要的角色产生变化也不需要修改代码,系统可扩展性强。


1.6 小结


以上的这些概念,也并非Spring Security独有,而是应用安全的基本关注点,Spring Security可以帮助我们更加快捷的完成认证和授权。很多时候,一个系统的安全性完全取决于系统开发人员的安全意识。例如,在我们从未听过SQL注入的时候,如何意识到要对SQL注入做防护?关于Web系统安全的攻击方式非常多,诸如:XSS、CSRF等,未来还会暴露出更多的攻击方式,我们只有在充分的了解其攻击原理后,才能提出完善而有效策略。在笔者看来,学习Spring Security并非局限于降低java应用的安全开发成本,通过Spring Security了解常见的安全攻击手段以及对应的防护手段也尤为重要,这些是脱离具体开发语言而存在的。


二、基于Session的认证方式



2.1 认证流程


基于Session认证方式的流程:

用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话),而发给客户端的sesssion_id存放到cookie中,这样用客户端请求时带上sesssion_id就可以验证服务器端是否存在session数据,以此完成用户的合法校验。当用户退出系统或session过期销毁时,客户端的session_id也就无效了。


下图是session认证方式的流程图:


4.png


基于Session的认证机制由Servlet规范定制,Servlet容器已实现,用户通过HttpSession的操作方法即可实现。


如下是HttpSession相关的操作API。


方法

含义

HttpSession getSession(Boolean create)

获取当前HttpSession对象

void setAttribute(String name,Object value) 向session中存放对象
object getAttribute(String name) 从session中获取对象
void removeAttribute(String name) 移除session中对象

void invalidate()

使 HttpSession 失效


2.2 创建工程


工程环境:使用maven进行构建,使用SpringMVC、Servlet3.0实现。


2.2.1 创建maven工程


5.png


工程结构


引入依赖如下:

1、 由于是web工程,packaging设置为war

2、 使用tomcat7-maven-plugin插件来运行工程


<?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>
    <groupId>com.uncle</groupId>
    <artifactId>security-springmvc</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>security-springmvc</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <configuration>
                        <encoding>utf-8</encoding>
                        <useDefaultDelimiters>true</useDefaultDelimiters>
                        <resources>
                            <resource>
                                <directory>src/main/resources</directory>
                                <filtering>true</filtering>
                                <includes>
                                    <include>**/*</include>
                                </includes>
                            </resource>
                            <resource>
                                <directory>src/main/java</directory>
                                <includes>
                                    <include>**/*.xml</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>


运行项目方式:


6.png


2.2.2 spring容器配置


在config包下定义ApplicationConfig.java,它对应web.xml中ContextLoaderListener的配置。


package com.uncle.security.springmvc.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 21:26
 */
@Configuration
@ComponentScan(basePackages = "com.uncle.security.springmvc"
        ,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)})
public class ApplicationConfig {
}


2.2.3 servletContext配置


本案例采用Servlet3.0无web.xml方式,在config包下定义WebConfig.java,它对应DispatcherServlet配置。


package com.uncle.security.springmvc.config;
import com.uncle.security.springmvc.interceptor.SimpleAuthenticationInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 21:34
 */
@Configuration//就相当于springmvc.xml文件
@EnableWebMvc
@ComponentScan(basePackages = "com.uncle.security.springmvc"
        ,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    SimpleAuthenticationInterceptor simpleAuthenticationInterceptor;
    //视频解析器
    @Bean
    public InternalResourceViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}


2.2.4 加载Spring容器


在init包下定义Spring容器初始化类SpringApplicationlnitializer,此类实现WebApplicationlnitializer接口, Spring容器启动时加载WebApplicationlnitializer接口的所有实现类。


package com.uncle.security.springmvc.init;
import com.uncle.security.springmvc.config.ApplicationConfig;
import com.uncle.security.springmvc.config.WebConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 21:47
 */
public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    //spring容器,相当于加载 applicationContext.xml
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{ApplicationConfig.class};
    }
    //servletContext,相当于加载springmvc.xml
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }
    //url-mapping
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}


SpringApplicationlnitializer相当于web.xml ,使用了servlet3.0开发则不需要再定义web.xml,ApplicationConfig.class对应以下配置的application-context.xml ,WebConfig.class对应以下配置的spring-mvc.xml , web.xml的内容参考:


<web-app>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/application-context .xml</param-value>
  </context-param>
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
      <init-param>
        <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-mvc.xml</param-value>
      </init-param>
    <load-on-startup>l</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>


2.3 实现认证功能


2.3.1 认证页面


在webapp/WEB-INF/views下定义认证页面login.jsp,页面实 现可填入用户名 密码,触发登录将提交表单信息至/login ,内容如下:


<%--
  Created by IntelliJ IDEA.
  User: uncle
  Date: 2021/7/22
  Time: 下午9:43
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %>
<html>
<head>
    <title>用户登录</title>
</head>
<body>
<form action="login" method="post">
    用户名:<input type="text" name="username"><br>
    密&nbsp;&nbsp;&nbsp;码:
    <input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>


在WebConfig中新增如下配置,将/直接导向login.jsp页面:


package com.uncle.security.springmvc.config;
import com.uncle.security.springmvc.interceptor.SimpleAuthenticationInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 21:34
 */
@Configuration//就相当于springmvc.xml文件
@EnableWebMvc
@ComponentScan(basePackages = "com.uncle.security.springmvc"
        ,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    SimpleAuthenticationInterceptor simpleAuthenticationInterceptor;
    //视频解析器
    @Bean
    public InternalResourceViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("login");
    }
}


启动项目,访问/路径地址,进行测试


启动


7.png


点击控制台生成的地址


8.png


2.3.2 认证接口


用户进入认证页面,输入账号和密码,点击登录,请求/login进行身份认证。


定义认证接口,此接口用于对传来的用户名、密码校验,若成功则返回该用户的详细信息,否则抛出错误异常:

package com.uncle.security.springmvc.service;
import com.uncle.security.springmvc.model.AuthenticationRequest;
import com.uncle.security.springmvc.model.UserDto;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 23:22
 */
public interface AuthenticationService {
    /**
     * 用户认证
     * @param authenticationRequest 用户认证请求,账号和密码
     * @return 认证成功的用户信息
     */
    UserDto authentication(AuthenticationRequest authenticationRequest);
}

认证请求结构:


package com.uncle.security.springmvc.model;
import lombok.Data;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 23:25
 */
@Data
public class AuthenticationRequest {
    //认证请求参数,账号、密码。
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
}


认证成功后返回的用户详细信息,也就是当前登录用户的信息:


package com.uncle.security.springmvc.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 23:25
 */
@Data
@AllArgsConstructor
public class UserDto {
    //用户身份信息
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
}


认证实现类,根据用户名查找用户信息,并校验密码,这里模拟了两个用户:


package com.uncle.security.springmvc.service;
import com.uncle.security.springmvc.model.AuthenticationRequest;
import com.uncle.security.springmvc.model.UserDto;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 23:27
 */
@Service
public class AuthenticationServiceImpl implements  AuthenticationService{
    /**
     * 用户认证,校验用户身份信息是否合法
     *
     * @param authenticationRequest 用户认证请求,账号和密码
     * @return 认证成功的用户信息
     */
    @Override
    public UserDto authentication(AuthenticationRequest authenticationRequest) {
        //校验参数是否为空
        if(authenticationRequest == null
                || StringUtils.isEmpty(authenticationRequest.getUsername())
                || StringUtils.isEmpty(authenticationRequest.getPassword())){
            throw new RuntimeException("账号和密码为空");
        }
        //根据账号去查询数据库,这里测试程序采用模拟方法
        UserDto user = getUserDto(authenticationRequest.getUsername());
        //判断用户是否为空
        if(user == null){
            throw new RuntimeException("查询不到该用户");
        }
        //校验密码
        if(!authenticationRequest.getPassword().equals(user.getPassword())){
            throw new RuntimeException("账号或密码错误");
        }
        //认证通过,返回用户身份信息
        return user;
    }
    //根据账号查询用户信息
    private UserDto getUserDto(String userName){
        return userMap.get(userName);
    }
    //用户信息
    private Map<String,UserDto> userMap = new HashMap<>();
    {
        userMap.put("zhangsan",new UserDto("1010","zhangsan","123","张三","133443"));
        userMap.put("lisi",new UserDto("1011","lisi","456","李四","144553"));
    }
}


登录Controller,对/login请求处理,它调用AuthenticationService完成认证并返回登录结果提示信息:


package com.uncle.security.springmvc.controller;
import com.uncle.security.springmvc.model.AuthenticationRequest;
import com.uncle.security.springmvc.model.UserDto;
import com.uncle.security.springmvc.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 23:33
 */
@RestController
public class LoginController {
    @Autowired
    AuthenticationService authenticationService;
    @RequestMapping(value = "/login",produces = "text/plain;charset=utf-8")
    public String login(AuthenticationRequest authenticationRequest, HttpSession session){
        UserDto userDto = authenticationService.authentication(authenticationRequest);
        return userDto.getUsername() +"登录成功";
    }
}


启动项目,访问/路径地址,进行测试

启动


7.png


点击控制台生成的地址


8.png


填入错误的用户信息,页面返回错误信息:

11.png


填入正确的用户信息,页面提示登录成功:


12.png


以上的测试全部符合预期,到目前为止最基础的认证功能已经完成,它仅仅实现了对用户身份凭证的校验,若某用户认证成功,只能说明他是该系统的一个合法用户,仅此而已。


2.4 实现会话功能


会话是指用户登入系统后,系统会记住该用户的登录状态,他可以在系统连续操作直到退出系统的过程。认证的目的是对系统资源的保护,每次对资源的访问,系统必须得知道是谁在访问资源,才能对该请求进行合法性拦截。因此,在认证成功后,一般会把认证成功的用户信息放入Session中,在后续的请求中,系统能够从Session中获取到当前用户,用这样的方式来实现会话机制。


1、增加会话控制

首先在UserDto中定义一个SESSION_USER_KEY ,作为Session中存放登录用户信息的key。


package com.uncle.security.springmvc.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
/**
 * @program: security-springmvc
 * @description:
 * @author: 步尔斯特
 * @create: 2021-07-22 23:25
 */
@Data
@AllArgsConstructor
public class UserDto {
    public static final String SESSION_USER_KEY = "_user";
    //用户身份信息
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
}
相关实践学习
消息队列+Serverless+Tablestore:实现高弹性的电商订单系统
基于消息队列以及函数计算,快速部署一个高弹性的商品订单系统,能够应对抢购场景下的高并发情况。
云安全基础课 - 访问控制概述
课程大纲 课程目标和内容介绍视频时长 访问控制概述视频时长 身份标识和认证技术视频时长 授权机制视频时长 访问控制的常见攻击视频时长
相关文章
|
21天前
|
编解码 NoSQL Java
使用Spring Boot + Redis 队列实现视频文件上传及FFmpeg转码的技术分享
【8月更文挑战第30天】在当前的互联网应用中,视频内容的处理与分发已成为不可或缺的一部分。对于视频平台而言,高效、稳定地处理用户上传的视频文件,并对其进行转码以适应不同设备的播放需求,是提升用户体验的关键。本文将围绕使用Spring Boot结合Redis队列技术来实现视频文件上传及FFmpeg转码的过程,分享一系列技术干货。
60 3
|
2月前
|
安全 Java 数据安全/隐私保护
使用Spring Security实现细粒度的权限控制
使用Spring Security实现细粒度的权限控制
|
2月前
|
安全 Java 数据库
实现基于Spring Security的权限管理系统
实现基于Spring Security的权限管理系统
|
2月前
|
安全 Java 数据安全/隐私保护
解析Spring Security中的权限控制策略
解析Spring Security中的权限控制策略
|
11天前
|
前端开发 JavaScript Java
技术分享:使用Spring Boot3.3与MyBatis-Plus联合实现多层次树结构的异步加载策略
在现代Web开发中,处理多层次树形结构数据是一项常见且重要的任务。这些结构广泛应用于分类管理、组织结构、权限管理等场景。为了提升用户体验和系统性能,采用异步加载策略来动态加载树形结构的各个层级变得尤为重要。本文将详细介绍如何使用Spring Boot3.3与MyBatis-Plus联合实现这一功能。
44 2
|
3月前
|
JSON 安全 Java
Spring Security 6.x 微信公众平台OAuth2授权实战
上一篇介绍了OAuth2协议的基本原理,以及Spring Security框架中自带的OAuth2客户端GitHub的实现细节,本篇以微信公众号网页授权登录为目的,介绍如何在原框架基础上定制开发OAuth2客户端。
153 4
Spring Security 6.x 微信公众平台OAuth2授权实战
|
3月前
|
存储 安全 Java
Spring Security 6.x OAuth2登录认证源码分析
上一篇介绍了Spring Security框架中身份认证的架构设计,本篇就OAuth2客户端登录认证的实现源码做一些分析。
144 2
Spring Security 6.x OAuth2登录认证源码分析
|
3月前
|
安全 Java 数据安全/隐私保护
Spring Security 6.x 一文快速搞懂配置原理
本文主要对整个Spring Security配置过程做一定的剖析,希望可以对学习Spring Sercurity框架的同学所有帮助。
181 5
Spring Security 6.x 一文快速搞懂配置原理
|
3月前
|
安全 Java API
Spring Security 6.x 图解身份认证的架构设计
【6月更文挑战第1天】本文主要介绍了Spring Security在身份认证方面的架构设计,以及主要业务流程,及核心代码的实现
58 1
Spring Security 6.x 图解身份认证的架构设计
|
2月前
|
安全 Java 数据安全/隐私保护
使用Spring Security实现细粒度的权限控制
使用Spring Security实现细粒度的权限控制