security 订阅
网络安全技术及其协议,包括了网络通信安全、信息在网络传输中的保密性和完整性、控制访问受限网域与敏感信息以及在公共网络如因特网上使用隐秘通讯。为了解决这些问题,各大组织及技术供应商纷纷推出了各种网络和信息安全技术。 展开全文
网络安全技术及其协议,包括了网络通信安全、信息在网络传输中的保密性和完整性、控制访问受限网域与敏感信息以及在公共网络如因特网上使用隐秘通讯。为了解决这些问题,各大组织及技术供应商纷纷推出了各种网络和信息安全技术。
信息
外文名
Security
包括了
网络通信安全
中文名
网络安全技术及其协议
推出了
各种网络和信息安全技术
Security基本介绍
Security:网络安全技术及其协议(Network Security Technologies and Protocols:AAA,VPN and Firewall)
收起全文
精华内容
下载资源
问答
  • 2022-03-20 15:06:46

    Spring Boot 使用Spring security

    Spring Boot与Spring Security在一起开发非常简单,充分体现了自动装配的强大,Spring Security是Spring Boot官方推荐使用的安全框架。配置简单,功能强大。接下来将说说Spring Boot使用Spring security进行安全控制。

    1.Spring Boot 内置属性参数

    Spring Boot 提供的内置配置参数以security为前缀,具体属性如下:

    # SECURITY (SecurityProperties 类中)
    security.basic.authorize-mode=role # 应用授权模式,ROLE=成员必须是安全的角色,AUTHENTICATED=经过身份验证的用户,NONE=没有设置安全授权
    security.basic.enabled=true # 启用基本身份认证
    security.basic.path=/** # 拦截策略,以逗号分隔
    security.basic.realm=Spring # HTTP基本realm
    security.enable-csrf=false # 启用csrf支持
    security.filter-order=0 # 过滤器执行顺序
    security.filter-dispatcher-types=ASYNC, FORWARD, INCLUDE, REQUEST # security 过滤器链dispatcher类型
    security.headers.cache=true # 启用缓存控制 HTTP headers.
    security.headers.content-type=true # 启用 “X-Content-Type-Options” header.
    security.headers.frame=true # 启用 “X-Frame-Options” header.
    security.headers.hsts= # HTTP Strict Transport Security (HSTS) mode (none, domain, all).
    security.headers.xss=true # 启用跨域脚本 (XSS) 保护.
    security.ignored= # 安全策略,以逗号分隔
    security.require-ssl=false # 启用所有请求SSL
    security.sessions=stateless # Session 创建策略(always, never, if_required, stateless).
    security.user.name=user # 默认用户名
    security.user.password= # 默认用户名密码
    security.user.role=USER # 默认用户角色

    # SECURITY OAUTH2 CLIENT (OAuth2ClientProperties 类中)
    security.oauth2.client.client-id= # OAuth2 client id.
    security.oauth2.client.client-secret= # OAuth2 client secret. A random secret is generated by default

    # SECURITY OAUTH2 RESOURCES (ResourceServerProperties 类中)
    security.oauth2.resource.id= # Identifier of the resource.
    security.oauth2.resource.jwt.key-uri= # The URI of the JWT token. Can be set if the value is not available and the key is public.
    security.oauth2.resource.jwt.key-value= # The verification key of the JWT token. Can either be a symmetric secret or PEM-encoded RSA public key.
    security.oauth2.resource.prefer-token-info=true # Use the token info, can be set to false to use the user info.
    security.oauth2.resource.service-id=resource #
    security.oauth2.resource.token-info-uri= # URI of the token decoding endpoint.
    security.oauth2.resource.token-type= # The token type to send when using the userInfoUri.
    security.oauth2.resource.user-info-uri= # URI of the user endpoint.

    # SECURITY OAUTH2 SSO (OAuth2SsoProperties 类中)
    security.oauth2.sso.filter-order= # Filter order to apply if not providing an explicit WebSecurityConfigurerAdapter
    security.oauth2.sso.login-path=/login # Path to the login page, i.e. the one that triggers the redirect to the OAuth2 Authorization Server

    以上是官方给出的配置属性以及默认值列表。

    2.security Starter Poms

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

    3.security hello world

    3.1创建工程

    创建工程springboot-security并加入security Starter Poms,完整代码如下:

    <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.chengli</groupId>
    	<artifactId>springboot-security</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    	<name>springboot-security</name>
    	<url>http://maven.apache.org</url>
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>1.4.3.RELEASE</version>
    	</parent>
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<java.version>1.8</java.version>
    	</properties>
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter</artifactId>
    		</dependency>
    		<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>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-devtools</artifactId>
    			<optional>true</optional>
    		</dependency>
    	</dependencies>
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    </project>
    

    3.2创建入口启动类

    package com.chengli.springboot;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @SpringBootApplication
    @EnableWebSecurity //启用web安全
    public class MainConfig {
    	public static void main(String[] args) {
    		SpringApplication.run(MainConfig.class, args);
    	}
    
    	@RequestMapping("/security")
    	public String security() {
    		return "hello world security";
    	}
    }
    

    3.3创建application.properties

    在application.properties中设置默认用户名以及默认密码

    security.user.name=chengli
    security.user.password=123456
    

    3.4启动

    到这里我们直接运行MainConfig试试吧,在浏览器上输入:http://localhost:8080/security,Spring security会为我们提供一个默认的登录页面,界面如下:

    输入用户名密码登录进去,页面上会显示hello world security。

    4.自定义security

    实际开发中,不可能都用security提供的默认配置,我们需要自定义一些配置,比如拦截的请求路径,以及从数据库中获取用户等等,那么接下来说说一些常用的配置。以下代码建立在以上工程中。

    4.1新建security配置类:SecurityConfig

    新建SecurityConfig类并继承WebSecurityConfigurerAdapter,WebSecurityConfigurerAdapter是security提供用于更改默认配置,实现configure方法,代码如下:

    package com.chengli.springboot.security;
    
    import org.springframework.context.annotation.Configuration;
    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;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    	
    	/**定义认证用户信息获取来源,密码校验规则等*/
    	@Override
    	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    		//inMemoryAuthentication 从内存中获取
    		auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER");
    		
    		//jdbcAuthentication从数据库中获取,但是默认是以security提供的表结构
    		//usersByUsernameQuery 指定查询用户SQL
    		//authoritiesByUsernameQuery 指定查询权限SQL
    		//auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query);
    		
    		//注入userDetailsService,需要实现userDetailsService接口
    		//auth.userDetailsService(userDetailsService);
    	}
    	
    	/**定义安全策略*/
    	@Override
    	protected void configure(HttpSecurity http) throws Exception {
    		http.authorizeRequests()//配置安全策略
    			.antMatchers("/","/hello").permitAll()//定义/请求不需要验证
    			.anyRequest().authenticated()//其余的所有请求都需要验证
    			.and()
    		.logout()
    			.permitAll()//定义logout不需要验证
    			.and()
    		.formLogin();//使用form表单登录
    	}
    	
    }
    

    4.2在入口启动类MainConfig加入以下方法

    这里为了方便演示就在加入一个方法

    @RequestMapping("/hello")
    	public String hello() {
    		return "不验证哦";
    	}
    

    4.4启动

    启动后,在浏览器上输入:http://localhost:8080/hello,我们看到是不需要验证直接在页面上输出:不验证哦。那在输入:http://localhost:8080/security,我们看到是需要进行验证的,那么输入用户名:chengli,密码:123456,我们看到页面输出:hello world security。这里为了方便演示用户信息是放在内存中,实际项目中使用数据库验证可以使用jdbc也可以实现userDetailsService类。

    4.5开启方法权限校验

    在SecurityConfig类加上注解:@EnableGlobalMethodSecurity,该注解可以开启prePostEnabled,securedEnabled,jsr250Enabled的支持,这里演示使用@EnableGlobalMethodSecurity(prePostEnabled = true),开启对prePostEnabled 支持。在方法上加入@PreAuthorize注解,@PreAuthorize注解支持使用SpEL表达式。这里我们在MainConfig类中加入以下代码:

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    	@RequestMapping("/authorize")
    	public String authorize() {
    		return "有权限访问";
    	}
    

    在增加一个用户admin,修改以下代码,如下:

    修改前:
    auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER")
    修改后:
    auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER")
    		.and().withUser("admin").password("123456").roles("ADMIN");
    

    这里我们在启动使用chengli登录后访问/authorize会返回403错误,使用admin登录访问页面输出有权限访问。

    既然登录了那就有退出,默认的退出地址在LogoutConfigurer类中,当然也是可以自定义的,这里就不说了,在定义安全策略方法中调用即可。我们也可以在浏览器中输入logout退出,这里会出现错误,因为security默认开启了csrf,这里我为了方便就禁用了csrf。禁用代码如下:

    //禁用csrf
    		http.csrf().disable();
    

    这里对于spring security的内容就不介绍了,具体的看官方文档。

    如果想学习Spring security 又对英文的文档望而生怯的话,那么给大家推荐一个系列博文:http://www.iteye.com/blogs/subjects/spring_security,作者写的还比较清楚就是版本相对于现在来说有点低,如果想学习新的特性那么还是看官方的文档吧。

    更多相关内容
  • SpringSecurity5+Element UI+Vue Admin Template+蚂蚁可视化AntV 等技术栈开发的项目,采用分布式,多模块,前后端分离开发。包括图形展示、权限管理、用户管理等功能。 【后端技术】 技术 说明...
  • spring security 4 需要 jar 包

    千次下载 热门讨论 2014-05-19 16:30:20
    spring security4 下载地址 http://repo.spring.io/snapshot/org/springframework/security/spring-security/4.0.0.CI-SNAPSHOT/ 所需要 jar 包 apacheds-core-1.5.5.jar aspectjrt-1.6.10.BUILD-20100810.234950-5...
  • SpringSecurity 简单使用

    千次阅读 2022-01-25 10:57:11
    SpringSecurity 简单使用 在 Web 开发中安全是不可忽视的问题(软件安全技术!),现在从 SpringSecurity 和 Shiro 两个框架来学习一下安全框架在 Web 应用中的使用。 Spring Security is a powerful and highly ...

    SpringSecurity 简单使用

    在 Web 开发中安全是不可忽视的问题(软件安全技术!),现在从 SpringSecurity 和 Shiro 两个框架来学习一下安全框架在 Web 应用中的使用。

    Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.

    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.

    Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是保护基于Spring的应用程序的事实标准。

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

    在 Web 开发中,安全是非常重要的一个方面。Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分,这两种需求 Spring Security 框架都有很好的支持。在用户认证方面,Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等。在用户授权方面,Spring Security 提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制。

    简单来说,SpringSecurity 框架可以进行用户认证和授权,简化了原本 Web 应用中过滤器、拦截器冗余的代码!

    1. 环境搭建

    新建项目 SpringBoot-07-Security,添加 Web 模块和 Thymeleaf 模块。

    然后在项目中导入静态资源(css、js、html),在 static 和 templates 目录下,资源引用自

    https://gitee.com/cao_jianhua/spring-security?_from=gitee_search

    目录结构:(resource)

    static

    —qiyuan

    ——css

    ——js

    templates

    —index.html

    —views

    ——level1

    ———1.html

    ———2.html

    ———3.html

    ——level2()

    ——level3()

    ——login.html

    然后在配置文件中关闭 Thymeleaf 的缓存

    spring.thymeleaf.cache=false
    

    再写一个控制器尝试访问一下页面

    @Controller
    public class RouterController {
        // 使用多个请求,要用 { } 括起来表明是数组!
        @RequestMapping({"/","/index"})
        public String index(){
            return "index";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin(){
            return "views/login";
        }
    
        // 按照请求的等级和 id 进入对应的页面
        @RequestMapping("/level1/{id}")
        public String level1(@PathVariable("id")int id){
            return "views/level1/"+id;
        }
        @RequestMapping("/level2/{id}")
        public String level2(@PathVariable("id")int id){
            return "views/level2/"+id;
        }
        @RequestMapping("/level3/{id}")
        public String level3(@PathVariable("id")int id){
            return "views/level3/"+id;
        }
    }
    

    通过请求能访问到页面,环境搭建就完成了!

    2. 用户认证和授权

    为了用 SpringSecurity 实现安全控制,需要引入 spring-boot-starter-security 依赖!

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

    在使用前,先了解三个重要的类和注解

    • WebSecurityConfigrerAdapter:自定义 Security 策略
    • AuthenticationManagerBuilder:自定义认证策略
    • @EnableWebSecurity:开启 WebSecurity 模式(@Enable 就是开启!)

    SpringSecurity 的主要目标就是认证授权

    2.1 用户授权

    导入相关依赖后,需要进行 SpringSecurity 的配置,在 com.qiyuan.config 包下创建 SecurityConfig 类,继承 WebSecurityConfigrerAdapter

    使用 Ctrl + O 可以查看父类方法并重写 configure(HttpSecurity http) 方法,进行授权的设置(重写的内容可以在源码的注释中查看!)

    // AOP 拦截器
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        // 授权
        protected void configure(HttpSecurity http) throws Exception {
            // 链式编程
            // 请求授权的设置
            http.authorizeRequests()
                    .antMatchers("/","/index").permitAll()
                    .antMatchers("/level1/**").hasRole("VIP1")
                    .antMatchers("/level2/**").hasRole("VIP2")
                    .antMatchers("/level3/**").hasRole("VIP3");
            // 没有权限前往登录页面
            http.formLogin();
        }
    }
    

    其中可以直接设定前往某页面所需的权限,再通过 formLogin() 方法使无权限的前往登录页面(这个登录页页面甚至是 SpringSecurity 自带的,请求为 /login)。

    2.2 用户认证

    再重写 configure(AuthenticationManagerBuilder auth) 方法进行认证的设置

    // AOP 拦截器
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        ...
    
        @Override
        // 认证
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // auth.jdbcAuthentication() 从数据库获取认证信息
            // 现在没有数据库,只能从内存中获取认证信息
            auth.inMemoryAuthentication()
                    .withUser("qiyuanc1").password("0723").roles("VIP1")
                    .and()
                    .withUser("qiyuanc2").password("0723").roles("VIP1","VIP2")
                    .and()
                    .withUser("qiyuanc3").password("0723").roles("VIP1","VIP2","VIP3");
        }
    }
    

    如果就这样运行,按照设置好的用户名密码登录时会报错:There is no PasswordEncoder mapped for the id "null",这是因为将用户名密码保存在内存中,需要对密码进行加密,防止反编译!SpringSecurity 推荐使用 BCrypt 加密方式,修改代码为

    // AOP 拦截器
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        ...
    
        @Override
        // 认证
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // auth.jdbcAuthentication() 从数据库获取认证信息
            // 现在没有数据库,只能从内存中获取认证信息
            auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                    .withUser("qiyuanc1").password(new BCryptPasswordEncoder().encode("0723")).roles("VIP1")
                    .and()
                    .withUser("qiyuanc2").password(new BCryptPasswordEncoder().encode("0723")).roles("VIP1","VIP2")
                    .and()
                    .withUser("qiyuanc3").password(new BCryptPasswordEncoder().encode("0723")).roles("VIP1","VIP2","VIP3");
        }
    }
    

    这样内存中的身份验证就搞定了,但 JDBC 身份验证还没试过,具体参考

    https://docs.spring.io/spring-security/site/docs/5.2.0.RELEASE/reference/htmlsingle/#jc-authentication-inmemory

    后面综合到一起的时候再做。

    3. 注销及权限控制

    3.1 注销

    和开启 SpringSecurity 自带的登录功能一样,一句话开启注销功能,对应的请求默认为 /logout

            // 没有权限前往登录页面
            http.formLogin();
            // 开启注销功能
            http.logout();
    

    然后在前端添加发起注销请求的按钮

    <a class="item" th:href="@{/logout}">
        <i class="sign-out icon"></i> 注销
    </a>
    

    这样就能注销当前登录的用户了,不过注销后默认会回到登录界面,再进行设置使注销后回到首页

            // 开启注销功能,注销成功回到首页
            http.logout().logoutSuccessUrl("/");
    

    这样注销功能就非常完善了!

    3.2 权限控制

    现在又有了新的权限控制问题:对于不同的角色(如 VIP1 和 VIP2)和不同的状态(登录和未登录),他们看同一页面的内容应该是不同的。如,VIP1 应该无法看到 level2 的内容;登录用户不用看到登录按钮,而要看到注销按钮;未登录用户不用看到注销按钮,而要看到登录按钮。这就是真实网站的情况!

    想要实现这种涉及前端显示的权限控制,当然需要前端页面的支持,结合 Thymeleaf 中的一些功能。

    导入 Thymeleaf 扩展 SpringSecurity 的依赖

    <!-- Thymeleaf 扩展 SpringSecurity -->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        <version>3.0.4.RELEASE</version>
    </dependency>
    

    还需要在前端页面导入命名空间

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

    然后在前端页面中,使用 Thymeleaf 的 sec:authorize 标签及 isAuthenticated() 方法判断当前角色是否经过验证;

    如未登录时,该标签取非判断生效,显示登录按钮

    <!--如果没有登录-->
    <div sec:authorize="!isAuthenticated()">
        <a class="item" th:href="@{/login}">
            <i class="address card icon"></i> 登录
        </a>
    </div>
    

    以及登录后,该标签本身判断生效,显示用户名、角色及注销按钮

    <div sec:authorize="isAuthenticated()">
        <!--如果登录则显示 用户名 角色-->
        <a class="item">
            用户名:<span sec:authentication="name"></span>
            角色:<span sec:authentication="authorities"></span>
        </a>
    </div>
    <div sec:authorize="isAuthenticated()">
        <!--如果登录则显示 注销-->
        <a class="item" th:href="@{/logout}">
            <i class="sign-out icon"></i> 注销
        </a>
    </div>
    

    这样登录和未登录用户的界面就区分开了!

    现在还剩下一个问题:不同权限的用户应该要看到不同的内容。同样使用 sec:authorize 标签和 hasAuthority() 方法实现

    <div class="ui raised segment" sec:authorize="hasAuthority('ROLE_VIP1')">
        <!-- VIP1 的内容 -->
    </div>
    <div class="ui raised segment" sec:authorize="hasAuthority('ROLE_VIP2')">
        <!-- VIP2 的内容 -->
    </div>
    <div class="ui raised segment" sec:authorize="hasAuthority('ROLE_VIP3')">
        <!-- VIP3 的内容 -->
    </div>
    

    前端通过获取当前用户的权限信息,判断是否显示某些内容!如此权限控制也完成了!

    4. 记住我及定制登录页

    4.1 记住我

    记住我是一个非常常用且实用的功能,避免了进入同一个网站需要多次登录的情况。在 SpringSecurity 框架的帮助下,想要开启记住我功能,只需在 configure(HttpSecurity http) 中开启

            // 开启记住我功能
            http.rememberMe();
    

    这样在自带的登录页上就会出现记住我的选项了!

    选择记住我并登录后,在浏览器的控制台中查看 Cookie,可以看到出现了一条名为 remember-me 的 Cookie,默认保留14天,这就是 SpringSecurity 帮我们创建的了

    注销时,SpringSecurity 又会将这条 Cookie 设置为空

    使用记住我后免登录的流程为:登录成功后,服务器将 Cookie 发送给浏览器于本地保存,以后发起请求时带上这条 Cookie,服务器检查通过则不用登陆;注销操作则会删除这个 Cookie。

    4.2 定制登录页

    之前使用的登录页面都是 SpringSecurity 自带的,虽然也挺好看的,但实际业务中还是要使用自己写的。

    想要更换登录页面,只需添加 http.formLogin() 的设置,如

            http.formLogin().loginPage("/toLogin");
    

    这样前往登录页面的请求就是 /toLogin 了,同时官方的登录页面已经被覆盖,前端的登录请求也需要由 /login 修改为 /toLogin

    这就产生了一个问题:之前使用官方的登录页面,SpringSecurity 可以直接获取我们登录的参数,现在使用了自己的登录页面,要怎么把参数交给 SpringSecurity 呢?

    解决方法同上,也是扩展 http.formLogin() 的设置即可

            http.formLogin()
                    .loginPage("/toLogin")
                    // 登录需要的参数
                    .usernameParameter("username")
                    .passwordParameter("password")
                    // 登录请求交给 SpringSecurity
                    .loginProcessingUrl("/login");
    

    为了让 SpringSecurity 获得登录的参数,需要配置接收的参数,即 username 和 password;同时要设置将登录请求提交给 /login,即交给 SpringSecurity 处理。

    之前添加的记住我功能也需要扩展配置,前端添加记住我的选择栏,提交参数为 remeber

    <div class="field">
        <input type="checkbox" name="remember">记住我
    </div>
    

    然后添加 http.remeberMe() 的设置

            http.rememberMe().rememberMeParameter("remeber");
    

    最后还会遇到一个问题:注销请求 /logout 找不到页面。这是由于 SpringSecurity 开启了 CSRF 防御功能导致的,logout 请求需要以 post 方式提交才可以。不过由于链接不是表单,不好调整,可以直接关闭此功能

            // 关闭 csrf 防御
            http.csrf().disable();
    

    至此使用自己的登录页面,所有功能都是成功的了!其实就相当于套了层皮(自己的登录页),实际的登录参数仍要交给 SpringSecurity 去处理,只要配置好数据的转发就好了。

    5. 总结

    对 SpringSecurity 框架简单地使用后发现,它其实就是对过滤器和拦截器进行了封装,使得进行认证和授权变得更加简单,同时它还运用了 AOP 的方式,不影响之前的代码,只要横切进去,管理安全相关的事务就可以了。非常好用,下次还用😋!

    展开全文
  • SpringSecurity源码

    千次下载 热门讨论 2014-05-29 08:53:28
    SpringSecurity教程配套源码 专栏地址:http://blog.csdn.net/column/details/springsecurity.html
  • Spring Security的基础使用

    千次阅读 2022-03-10 18:46:04
    什么是spring security 二. Spring security 的使用 1.创建springboot项目 2.主启动类 2.配置controller层 3.配置config类 4.配置多用户登录以及注入权限及登录config注入 5.配置config层 6.登录成功处理类...

    目录

    一. 什么是spring security

    二. Spring security 的使用

    1.创建springboot项目

     2.主启动类

    2.配置controller层

    3.配置config类

    4.配置多用户登录以及注入权限及登录config注入

    5.配置config层

    6.登录成功处理类及无权限处理类

    7.配置工具类

    8.启动测试

    三. 总结


    一. 什么是spring security

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安 全访问控制解决方案的安全框架。它提供了一组可以在Sprirg应用上下文 中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection依赖主入)和AOP(面向切面编程)功能,为应 用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写 大量重复代码的工作。 以上解释来源于百度白科。可以一句话来概括,SpringSecurity 是一个安全框架。可以帮我们完成认证,授权,密码加密,rememberme的功能。

    二. Spring security 的使用

    1.创建springboot项目

     2.主启动类

    package com.exy;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @SpringBootApplication
    public class SecurityApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SecurityApplication.class, args);
        }
    
        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    }
    

    2.配置controller层

    package com.exy.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @program: springsecurity-qy145-01
     * @description:
     * @author: 
     * @create: 2022-03-10 11:07
     * 只要账号登录 后 都可以访问所有的资源。
     *    1.ykq 进入可以访问 list  inser  delete update
     *    2.mcl 进入只能访问 list  export
     **/
    @RestController
    public class Test {
    
        @GetMapping("/list")
        public String list(){
    
            return "user:list";
        }
    
        @GetMapping("/insert")
        public String insert(){
    
            return "user:insert";
        }
    
        @GetMapping("/delete")
        public String delete(){
    
            return "user:delete";
        }
    
        @GetMapping("/update")
        public String update(){
    
            return "user:update";
        }
    
        @GetMapping("/export")
        public String export(){
    
            return "user:export";
        }
    }
    

    3.配置config类

    package com.exy.config;
    
    import com.exy.handle.MyAccessDeniedHandler;
    import com.exy.handle.SuccessHandler;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    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.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.parameters.P;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @program: security01
     * @description:
     * @author: jdy
     * @create: 2022-03-10 10:05
     **/
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private PasswordEncoder passwordEncoder;
        @Autowired
        private SuccessHandler successHandler;
        @Autowired
        private MyAccessDeniedHandler myAccessDeniedHandler;
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("jdy")
                    .password(passwordEncoder.encode("123132"))
                    .roles("admin")
                    .authorities("user:list","user:delete");
    
        }
    
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin().successHandler(successHandler).permitAll();
            http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);
    
            http.authorizeRequests()
                    .antMatchers("/list").hasAnyAuthority("user:list")
                    .antMatchers("/insert").hasAnyAuthority("user:insert")
                    .antMatchers("/update").hasAnyAuthority("user:update")
                    .antMatchers("/delete").hasAnyAuthority("user:delete")
                    .antMatchers("/export").hasAnyAuthority("user:export");
        }
    }

    4.配置多用户登录以及注入权限及登录config注入

    package com.exy.config;
    
    import com.exy.handle.MyAccessDeniedHandler;
    import com.exy.handle.SuccessHandler;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    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.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.parameters.P;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @program: security01
     * @description:
     * @author: jdy
     * @create: 2022-03-10 10:05
     **/
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private PasswordEncoder passwordEncoder;
        @Autowired
        private SuccessHandler successHandler;
        @Autowired
        private MyAccessDeniedHandler myAccessDeniedHandler;
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("jdy")
                    .password(passwordEncoder.encode("123132"))
                    .roles("admin")
                    .authorities("user:list","user:delete");
    
        }
    
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin().successHandler(successHandler).permitAll();
            http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);
    
            http.authorizeRequests()
                    .antMatchers("/list").hasAnyAuthority("user:list")
                    .antMatchers("/insert").hasAnyAuthority("user:insert")
                    .antMatchers("/update").hasAnyAuthority("user:update")
                    .antMatchers("/delete").hasAnyAuthority("user:delete")
                    .antMatchers("/export").hasAnyAuthority("user:export");
        }
    }

    5.配置config层

    package com.exy.config;
    
    import com.exy.handle.MyAccessDeniedHandler;
    import com.exy.handle.SuccessHandler;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    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.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.parameters.P;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @program: security01
     * @description:
     * @author: jdy
     * @create: 2022-03-10 10:05
     **/
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private PasswordEncoder passwordEncoder;
        @Autowired
        private SuccessHandler successHandler;
        @Autowired
        private MyAccessDeniedHandler myAccessDeniedHandler;
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("jdy")
                    .password(passwordEncoder.encode("123132"))
                    .roles("admin")
                    .authorities("user:list","user:delete");
    
        }
    
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin().successHandler(successHandler).permitAll();
            http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);
    
            http.authorizeRequests()
                    .antMatchers("/list").hasAnyAuthority("user:list")
                    .antMatchers("/insert").hasAnyAuthority("user:insert")
                    .antMatchers("/update").hasAnyAuthority("user:update")
                    .antMatchers("/delete").hasAnyAuthority("user:delete")
                    .antMatchers("/export").hasAnyAuthority("user:export");
        }
    }

    6.登录成功处理类及无权限处理类

    package com.exy.handle;
    
    import com.exy.util.CommonResult;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    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;
    
    /**
     * @program: security01
     * @description:
     * @author: jdy
     * @create: 2022-03-10 16:02
     **/
    
    @Component
    public class SuccessHandler implements AuthenticationSuccessHandler {
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            CommonResult commonResult = new CommonResult(2000, "登录成功", authentication);
            PrintWriter writer = response.getWriter();
            writer.print(new ObjectMapper().writeValueAsString(commonResult));
            writer.flush();
            writer.close();
        }
    }
    package com.exy.handle;
    
    import com.exy.util.CommonResult;
    import com.fasterxml.jackson.databind.ObjectMapper;
    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;
    
    /**
     * @program: security01
     * @description:
     * @author: jdy
     * @create: 2022-03-10 17:15
     **/
    @Component
    public class MyAccessDeniedHandler implements AccessDeniedHandler {
        @Override
        public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            CommonResult commonResult = new CommonResult(2000, "权限不足", accessDeniedException);
            PrintWriter writer = response.getWriter();
            writer.print(new ObjectMapper().writeValueAsString(commonResult));
            writer.flush();
            writer.close();
        }
    }

    7.配置工具类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    
    public class CommonResult {
        private int code;
        private String msg;
        private Object data;
    }

    8.启动测试

     

     

    三. 总结

    进入移动互联网时代,大家每天都在刷手机,常用的软件有微信、支付 宝、头条,抖音等,下边拿微信来举例子说明认证相关的基本概念,在初 次使用微信前需要注册成为微信用户,然后输入账号和密码即可登录微 信,输入账号和密码登录微信的过程就是认证。 系统为什么要认证? 认证是为了保护系统的隐私数据与资源,用户的身份合法,方可访问该系统 的资源。 认证︰用户认证就是判断一个用户的身份是否合法的过程,用户去访问系 统资源时系统要求验证用户的身份信息,身份合法 方可继续访问,不合法 则拒绝访问。常见的用户身份认证方式有:用户名密码登录,二维码登录, 手机短信登录,指纹认证等方式。

    展开全文
  • Spring Security 工作原理概览

    万次阅读 多人点赞 2019-04-27 08:02:58
    本文由读者 muggle 投稿,muggle 是一位具备极客精神的90后单身老实猿,对 Spring Security 有丰富的使用经验,muggle 个人博客地址是 h...

    本文由读者 muggle 投稿,muggle 是一位具备极客精神的90后单身老实猿,对 Spring Security 有丰富的使用经验,muggle 个人博客地址是 https://muggle0.github.io。

    Security 原理分析

    SpringSecurity 过滤器链

    SpringSecurity 采用的是责任链的设计模式,它有一条很长的过滤器链。现在对这条过滤器链的各个进行说明:

    1. WebAsyncManagerIntegrationFilter:将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。

    2. SecurityContextPersistenceFilter:在每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将 SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将 SecurityContextHolder 中的信息清除,例如在Session中维护一个用户的安全信息就是这个过滤器处理的。

    3. HeaderWriterFilter:用于将头信息加入响应中。

    4. CsrfFilter:用于处理跨站请求伪造。

    5. LogoutFilter:用于处理退出登录。

    6. UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自 /login 的请求。从表单中获取用户名和密码时,默认使用的表单 name 值为 username 和 password,这两个值可以通过设置这个过滤器的usernameParameter 和 passwordParameter 两个参数的值进行修改。

    7. DefaultLoginPageGeneratingFilter:如果没有配置登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。

    8. BasicAuthenticationFilter:检测和处理 http basic 认证。

    9. RequestCacheAwareFilter:用来处理请求的缓存。

    10. SecurityContextHolderAwareRequestFilter:主要是包装请求对象request。

    11. AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在 Authentication 对象,如果不存在为其提供一个匿名 Authentication。

    12. SessionManagementFilter:管理 session 的过滤器

    13. ExceptionTranslationFilter:处理 AccessDeniedException 和 AuthenticationException 异常。

    14. FilterSecurityInterceptor:可以看做过滤器链的出口。

    15. RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。

    SpringSecurity 流程图

    先来看下面一个 Spring Security 执行流程图,只要把 SpringSecurity 的执行过程弄明白了,这个框架就会变得很简单:

    640?wx_fmt=png

    流程说明

    1. 客户端发起一个请求,进入 Security 过滤器链。

    2. 当到 LogoutFilter 的时候判断是否是登出路径,如果是登出路径则到 logoutHandler ,如果登出成功则到 logoutSuccessHandler 登出成功处理,如果登出失败则由 ExceptionTranslationFilter ;如果不是登出路径则直接进入下一个过滤器。

    3. 当到 UsernamePasswordAuthenticationFilter 的时候判断是否为登录路径,如果是,则进入该过滤器进行登录操作,如果登录失败则到 AuthenticationFailureHandler 登录失败处理器处理,如果登录成功则到 AuthenticationSuccessHandler 登录成功处理器处理,如果不是登录请求则不进入该过滤器。

    4. 当到 FilterSecurityInterceptor 的时候会拿到 uri ,根据 uri 去找对应的鉴权管理器,鉴权管理器做鉴权工作,鉴权成功则到 Controller 层否则到 AccessDeniedHandler 鉴权失败处理器处理。

    Security 配置

    WebSecurityConfigurerAdapter 这个类里面可以完成上述流程图的所有配置

    配置类伪代码

    @Configuration	
    @EnableWebSecurity	
    public class SecurityConfig extends WebSecurityConfigurerAdapter {	
        @Override	
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {	
            auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder());	
        }	
        @Override	
        public void configure(WebSecurity web) throws Exception {	
            web.ignoring().antMatchers("/resources/**/*.html", "/resources/**/*.js");	
        }	
        @Override	
        protected void configure(HttpSecurity http) throws Exception {	
           http	
           .formLogin()	
           .loginPage("/login_page")	
           .passwordParameter("username")	
           .passwordParameter("password")	
           .loginProcessingUrl("/sign_in")	
           .permitAll()	
           .and().authorizeRequests().antMatchers("/test").hasRole("test")	
           .anyRequest().authenticated().accessDecisionManager(accessDecisionManager())	
           .and().logout().logoutSuccessHandler(new MyLogoutSuccessHandler())	
           .and().csrf().disable();	
           http.addFilterAt(getAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);	
           http.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler());	
           http.addFilterAfter(new MyFittler(), LogoutFilter.class);	
        }	
    }

    配置简介

    • configure(AuthenticationManagerBuilder auth)

    AuthenticationManager 的建造器,配置 AuthenticationManagerBuilder 会让Security 自动构建一个 AuthenticationManager(该类的功能参考流程图);如果想要使用该功能你需要配置一个 UserDetailService 和 PasswordEncoder。UserDetailsService 用于在认证器中根据用户传过来的用户名查找一个用户, PasswordEncoder 用于密码的加密与比对,我们存储用户密码的时候用PasswordEncoder.encode() 加密存储,在认证器里会调用 PasswordEncoder.matches() 方法进行密码比对。如果重写了该方法,Security 会启用 DaoAuthenticationProvider 这个认证器,该认证就是先调用 UserDetailsService.loadUserByUsername 然后使用 PasswordEncoder.matches() 进行密码比对,如果认证成功成功则返回一个 Authentication 对象。

    • configure(WebSecurity web)

    这个配置方法用于配置静态资源的处理方式,可使用 Ant 匹配规则。

    • configure(HttpSecurity http)

    这个配置方法是最关键的方法,也是最复杂的方法。我们慢慢掰开来说:

    http	
    .formLogin()	
    .loginPage("/login_page")	
    .passwordParameter("username")	
    .passwordParameter("password")	
    .loginProcessingUrl("/sign_in")	
    .permitAll()

    这是配置登录相关的操作从方法名可知,配置了登录页请求路径,密码属性名,用户名属性名,和登录请求路径,permitAll()代表任意用户可访问。

    http	
    .authorizeRequests()	
    .antMatchers("/test").hasRole("test")	
    .anyRequest().authenticated()	
    .accessDecisionManager(accessDecisionManager());

    以上配置是权限相关的配置,配置了一个 /test url 该有什么权限才能访问, anyRequest() 表示所有请求,authenticated() 表示已登录用户才能访问, accessDecisionManager() 表示绑定在 url 上的鉴权管理器

    为了对比,现在贴出另一个权限配置清单:

    http.authorizeRequests()	
    .antMatchers("/tets_a/**","/test_b/**").hasRole("test")	
    .antMatchers("/a/**","/b/**").authenticated()	
    .accessDecisionManager(accessDecisionManager())

    我们可以看到权限配置的自由度很高,鉴权管理器可以绑定到任意 url 上;而且可以硬编码各种 url 权限:

    http	
    .logout()	
    .logoutUrl("/logout")	
    .logoutSuccessHandler(new MyLogoutSuccessHandler())

    登出相关配置,这里配置了登出 url 和登出成功处理器:

    http	
    .exceptionHandling()	
    .accessDeniedHandler(new MyAccessDeniedHandler());

    上面代码是配置鉴权失败的处理器。

    http.addFilterAfter(new MyFittler(), LogoutFilter.class);	
    http.addFilterAt(getAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);

    上面代码展示如何在过滤器链中插入自己的过滤器,addFilterBefore 加在对应的过滤器之前,addFilterAfter 加在对应的过滤器之后,addFilterAt 加在过滤器同一位置,事实上框架原有的 Filter 在启动 HttpSecurity 配置的过程中,都由框架完成了其一定程度上固定的配置,是不允许更改替换的。根据测试结果来看,调用 addFilterAt 方法插入的 Filter ,会在这个位置上的原有 Filter 之前执行。

    注:关于 HttpSecurity 使用的是链式编程,其中 http.xxxx.and.yyyyy 这种写法和 http.xxxx;http.yyyy 写法意义一样。

    • 自定义 AuthenticationManager 和 AccessDecisionManager

    重写 authenticationManagerBean() 方法,并构造一个 authenticationManager:

    @Override	
    public AuthenticationManager authenticationManagerBean() throws Exception {	
        ProviderManager authenticationManager = new ProviderManager(Arrays.asLis(getMyAuthenticationProvider(),daoAuthenticationProvider()));	
        return authenticationManager;	
    }

    我这里给 authenticationManager 配置了两个认证器,执行过程参考流程图。

    定义构造AccessDecisionManager的方法并在配置类中调用,配置参考 configure(HttpSecurity http) 说明:

    public AccessDecisionManager accessDecisionManager(){	
        List<AccessDecisionVoter<? extends Object>> decisionVoters	
                = Arrays.asList(	
                new MyExpressionVoter(),	
                new WebExpressionVoter(),	
                new RoleVoter(),	
                new AuthenticatedVoter());	
        return new UnanimousBased(decisionVoters);	
    }

    投票管理器会收集投票器投票结果做统计,最终结果大于等于0代表通过;每个投票器会返回三个结果:-1(反对),0(通过),1(赞成)。

    Security 权限系统

    • UserDetails

    Security 中的用户接口,我们自定义用户类要实现该接口。

    • GrantedAuthority

    Security 中的用户权限接口,自定义权限需要实现该接口:

    public class MyGrantedAuthority implements GrantedAuthority {	
        private String authority;	
    }

    authority 表示权限字段,需要注意的是在 config 中配置的权限会被加上 ROLE_ 前缀,比如我们的配置 authorizeRequests().antMatchers("/test").hasRole("test"),配置了一个 test 权限但我们存储的权限字段(authority)应该是 ROLE_test

    • UserDetailsService

    Security 中的用户 Service,自定义用户服务类需要实现该接口:

    @Service	
    public class MyUserDetailService implements UserDetailsService {	
        @Override	
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {	
          return.....	
        }	
    }

    loadUserByUsername的作用在上文中已经说明,就是根据用户名查询用户对象。

    • SecurityContextHolder

    用户在完成登录后 Security 会将用户信息存储到这个类中,之后其他流程需要得到用户信息时都是从这个类中获得,用户信息被封装成 SecurityContext ,而实际存储的类是 SecurityContextHolderStrategy ,默认的SecurityContextHolderStrategy 实现类是 ThreadLocalSecurityContextHolderStrategy 它使用了ThreadLocal来存储了用户信息。

    手动填充 SecurityContextHolder 示例:

    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("test","test",list);	
    SecurityContextHolder.getContext().setAuthentication(token);

    对于使用 token 鉴权的系统,我们就可以验证token后手动填充SecurityContextHolder,填充时机只要在执行投票器之前即可,或者干脆可以在投票器中填充,然后在登出操作中清空SecurityContextHolder。

    Security 扩展

    Security 可扩展的有

    1. 鉴权失败处理器

    2. 验证器

    3. 登录成功处理器

    4. 投票器

    5. 自定义token处理过滤器

    6. 登出成功处理器

    7. 登录失败处理器

    8. 自定义 UsernamePasswordAuthenticationFilter

    • 鉴权失败处理器

    Security 鉴权失败默认跳转登录页面,我们可以实现 AccessDeniedHandler 接口,重写 handle() 方法来自定义处理逻辑;然后参考配置类说明将处理器加入到配置当中。

    • 验证器

    实现 AuthenticationProvider 接口来实现自己验证逻辑。需要注意的是在这个类里面就算你抛出异常,也不会中断验证流程,而是算你验证失败,我们由流程图知道,只要有一个验证器验证成功,就算验证成功,所以你需要留意这一点。

    • 登录成功处理器

    在 Security 中验证成功默认跳转到上一次请求页面或者路径为 "/" 的页面,我们同样可以自定义:继承 SimpleUrlAuthenticationSuccessHandler 这个类或者实现 AuthenticationSuccessHandler 接口。我这里建议采用继承的方式,SimpleUrlAuthenticationSuccessHandler 是默认的处理器,采用继承可以契合里氏替换原则,提高代码的复用性和避免不必要的错误。

    • 投票器

    投票器可继承 WebExpressionVoter 或者实现 AccessDecisionVoter接口;WebExpressionVoter 是 Security 默认的投票器;我这里同样建议采用继承的方式;添加到配置的方式参考 上文;

    注意:投票器 vote 方法返回一个int值;-1代表反对,0代表弃权,1代表赞成;投票管理器收集投票结果,如果最终结果大于等于0则放行该请求。

    • 自定义token处理过滤器

    自定义 token 处理器继承自 OncePerRequestFilter 或者 GenericFilterBean 或者 Filter 都可以,在这个处理器里面需要完成的逻辑是:获取请求里的 token,验证 token 是否合法然后填充 SecurityContextHolder ,虽然说过滤器只要添加在投票器之前就可以,但我这里还是建议添加在 http.addFilterAfter(new MyFittler(), LogoutFilter.class);

    • 登出成功处理器

    实现LogoutSuccessHandler接口,添加到配置的方式参考上文。

    • 登录失败处理器

    登录失败默认跳转到登录页,我们同样可以自定义。继承 SimpleUrlAuthenticationFailureHandler 或者实现 AuthenticationFailureHandler,建议采用继承。

    • 自定义UsernamePasswordAuthenticationFilter

    我们自定义UsernamePasswordAuthenticationFilter可以极大提高我们 Security的灵活性(比如添加验证验证码是否正确的功能)。

    我们直接继承 UsernamePasswordAuthenticationFilter ,然后在配置类中初始化这个过滤器,给这个过滤器添加登录失败处理器,登录成功处理器,登录管理器,登录请求 url 。

    这里配置略微复杂,贴一下代码清单

    初始化过滤器:

    MyUsernamePasswordAuthenticationFilte getAuthenticationFilter(){	
        MyUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter = new MyUsernamePasswordAuthenticationFilter(redisService);	
        myUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(new MyUrlAuthenticationFailureHandler());	
        myUsernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());	
        myUsernamePasswordAuthenticationFilter.setFilterProcessesUrl("/sign_in");	
        myUsernamePasswordAuthenticationFilter.setAuthenticationManager(getAuthenticationManager());	
        return myUsernamePasswordAuthenticationFilter;	
    }

    添加到配置:

    http.addFilterAt(getAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);

    总结

    对于 Security 的扩展配置关键在于 configure(HttpSecurityhttp) 方法;扩展认证方式可以自定义 authenticationManager 并加入自己验证器,在验证器中抛出异常不会终止验证流程;扩展鉴权方式可以自定义 accessDecisionManager 然后添加自己的投票器并绑定到对应的 url(url 匹配方式为 ant)上,投票器 vote(Authenticationauthentication,FilterInvocationfi,Collection<ConfigAttribute>attributes) 方法返回值为三种:-1 0 1,分别表示反对弃权赞成。

    对于 token 认证的校验方式,可以暴露一个获取的接口,或者重写 UsernamePasswordAuthenticationFilter 过滤器和扩展登录成功处理器来获取 token,然后在 LogoutFilter 之后添加一个自定义过滤器,用于校验和填充 SecurityContextHolder。

    另外,Security 的处理器大部分都是重定向的,我们的项目如果是前后端分离的话,我们希望无论什么情况都返回 json ,那么就需要重写各个处理器了。


    640 640关注牧码小子,后台回复 Java ,领取松哥为你精心准备的Java干货! 640 

    往期文章一览

    1、工作之余,你是怎么提高技术的?

    2、两年了,我写了这些干货!

    3、想和大家谈一点合作

    4、一个Java程序猿眼中的前后端分离以及Vue.js入门

    5、跟着平台混了四年,现在要单飞了!

    640?wx_fmt=png你点的每个在看,我都认真当成了喜欢


    展开全文
  • Spring Security介绍

    万次阅读 多人点赞 2020-11-03 12:59:24
    1、Spring Security的架构及核心组件:(1)认证;(2)权限拦截;(3)数据库管理;(4)权限缓存;(5)自定义决策; 2、环境搭建与使用,使用当前热门的Spring Boot来搭建环境,结合项目中实际的例子来做几个Case; 3、...
  • 11.Spring security跨域问题

    千次阅读 2022-03-26 16:03:36
    文章目录*跨域问题**11.1什么是CORS**11.2Spring处理方案**11.2.1`@CrossOrigin`**11.2.2`addCorsMappings`**11.2.3`CorsFilter`**11.3Spring Security处理方案**11.3.1特殊处理`OPTIONS`请求**11.3.2继续使用`...
  • 【springsecurity】简介,SpringSecurity

    千次阅读 2021-08-11 17:48:42
    // 都需要身份验证 } } org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter org.springframework.security.web.context.SecurityContextPersistenceFilter org.spring...
  • 菜鸟的spring security学习教程

    千次阅读 多人点赞 2020-05-31 00:07:29
    菜鸟的spring security学习教程说明一、Spring Security简介二、 说明 近期要用到spring security这个框架,由于spring security是之前学的,而且当时也没有深入的学习,对于该框架的用法有点陌生了,现重新学习...
  • SpringBoot+SpringSecurity+JWT实现认证和授权

    万次阅读 多人点赞 2021-01-17 23:40:52
    dbcp,c3p0) SpringBoot+SpringSecurity+mysql实现认证与授 SpringBoot+Spring Security基于内存用户认证 SpringBoot+WebSocket在线聊天室、消息推送 SpringBoot+SpringData JPA操作Mysql数据库 SpringBoot热部署...
  • 前后端分离系列 -- SpringBoot + Spring Security + Vue 实现用户认证 SpringSecurity如此简单
  • Spring Security 和 SpringCloud Security 有什么区别?
  • 最近在做ssm项目的时候用到spring security时遇到了异常,如下所示: 15:06:28,144 DEBUG FilterSecurityInterceptor:348 - Previously Authenticated: org.springframework.security.authentication....
  • HttpSecurity是Spring Security Config用于配置http请求安全控制的安全构建器(类似于Spring Security XML配置中的http命名空间配置部分),它的构建目标是一...该目标SecurityFilterChain最终会被Spring Security的安...
  • 小二是新来的实习生,作为技术 leader,我还是很负责任的,有什么好事都想着他,这不,我就安排了一个整合SpringSecurity+JWT实现登录认证的小任务交,没想到,他仅用四步就搞定了,这让我感觉倍有面。 一、关于 ...
  • Spring Security 完整实例

    热门讨论 2012-09-19 16:20:29
    完成的Spring Security实例,其中包括自定义数据库表结构、自定义登陆页面、使用数据库管理资源、自定义的密码编码器、自定义访问拒绝页面、动态管理资源结合自定义登录页面等方面的例子
  • 登录及退出 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" ... xmlns:security="http://www.springframework.org/schema/security" xmln
  • SpringBoot整合SpringSecurity(通俗易懂)

    万次阅读 多人点赞 2020-10-24 17:04:57
    先搭建项目正常访问,在pom.xml中,先把Spring Security依赖注释 <!--<dependency>--> <!--<groupId>org.springframework.boot</groupId>--> <!--<artifactId>spring-bo.
  • Spring Security初识和表单认证(二)

    千次阅读 2022-03-26 22:59:54
    1. Spring Security简介 Spring Security 的前身是 Acegi Security,在被收纳为Spring子项目后正式更名为Spring Security。 应用程序的安全性通常体现在两个方面:认证和授权。 认证是确认某主体在某系统中是否合法...
  • Security:Elastic Security 入门

    千次阅读 热门讨论 2021-01-18 11:49:35
    Elastic Security 使分析人员能够预防,检测和响应威胁。 这个免费开放的解决方案可提供SIEM,端点安全,威胁搜寻,云监视等功能。Elastic Security 由一下的两个部分组成: 在上面 Security app 指的就是在 ...
  • 背景介绍 针对传统蓝牙的产品, 提到安全等级时我们常常会听到mode 4...如上图所示,在security channel 建立过程会根据Responding device version(对端设备)的蓝牙版本来选择Security Mode, 这点也说明了一个设备为了兼
  • springsecurity详解

    万次阅读 多人点赞 2020-11-23 14:06:03
    1.springsecurity springsecurity底层实现为一条过滤器链,就是用户请求进来,判断有没有请求的权限,抛出异常,重定向跳转。 2.登录页 springsecurity自带一个登录页。 从登陆入手,登录页替换成我们自己的,...
  • 单点登录SSO解决方案之SpringSecurity+JWT实现

    万次阅读 多人点赞 2019-12-05 18:20:57
      通过前面几天文章我们详细的介绍了SpringSecurity的使用,本文我们来看下,结合JWT来实现单点登录操作。 一、什么是单点登陆   单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决...
  • 文章目录前言本篇博客做的内容项目创建环境、配置等增加未认证跳转页面配置类中增加无权访问页面跳转配置请求测试前后分离配置先创建无权监测类修改配置类测试代码下载 ...参照springboot-security-0
  • Spring——Security安全框架之注解使用

    千次阅读 2022-02-23 11:09:03
    之前security中,针对配置项进行了相关的配置和测试。 但是这些都是基于在security.config.MyConfig#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)中进行对应请求的权限...
  • SpringSecurity详解

    千次阅读 2022-03-31 20:17:49
    在之前,对springsecurity进行了一个简单介绍,并且上手了一个简单demo。这里是链接,需要的可以去看一下如何给用户分配权限?这篇文章主要为大家介绍一下,基于springSecurity对于角色和用户一些简单的权限判断。 ...
  • spring security CSRF防护

    万次阅读 多人点赞 2019-07-31 19:14:30
    从Spring Security 4.0开始,默认情况下会启用CSRF保护,以防止CSRF攻击应用程序,Spring Security CSRF会针对PATCH,POST,PUT和DELETE方法进行防护。 我这边是spring boot项目,在启用了@EnableWebSecurity...
  • SpringSecurity系列之授权与注解

    千次阅读 2022-01-29 14:54:37
    SpringSecurity用户授权与权限注解的使用

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,012,617
精华内容 405,046
关键字:

security