Spring Security(学习笔记) --Json登录的两种方式!

embedded/2024/10/18 8:28:36/

重点标识

Json登录。
Security默认是key-value的形式的。

前后端分离,Json处理比较方便。

Security默认是通过request.getpartmater这种方式获取,所以不支持。

自定义登录接口(方法一)

上一篇已经说过了,Spring容器里面是没有AuhtenticationManager,但是有AuhtenticationManagerBuilder。

创建一个登录接口:


@Controller
public class LoginController {@AutowiredAuthenticationManager authenticationManager;@PostMapping("/login")@ResponseBodypublic String login(@RequestBody User user, HttpSession session){//未认证令牌,参考UsernamePasswordAuthenticationFilter这个来写就行了try {UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(user.getUsername(), user.getPassword());Authentication auth = authenticationManager.authenticate(authRequest);//这里还有一点要注意,我们一般都是从SecurityContextHolder取到用户信息的,那这里也别忘了给他放进去SecurityContextHolder.getContext().setAuthentication(auth);//还有一点要注意,新版的Security是从session中获取的,那本次会话的下次请求想要拿到,也需要丢到session中去session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,SecurityContextHolder.getContext());return auth.getName();} catch (AuthenticationException e) {//throw new RuntimeException(e);//如果出现错误,这里简单点,就不封装了,直接返回好了return e.getMessage();}}
}

向Spring容器中注入一个AuthenticationManager 。


@Configuration
public class SecurityConfig {UserDetailsService userDetailsService(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("admin").password("{noop}123").build());return inMemoryUserDetailsManager;}@BeanAuthenticationManager authenticationManager(){DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService(userDetailsService());ProviderManager providerManager = new ProviderManager(daoAuthenticationProvider);return providerManager;}@BeanSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(a->a.requestMatchers("/login").permitAll().anyRequest().authenticated()).csrf(c->c.disable());return http.build();}}

User类也给大家


public class User {private String username;private String password;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

看一下测试结果:

在这里插入图片描述
再看一下,同一个会话中,另一个请求能不能获取到用户信息:

在这里插入图片描述
ok ,都没问题,实际上,像我们之前写的验证码,如果不想采用过滤器的形式,也可以通过自定义登录这种方式,写在authenticate之前,try里面,这样验证错误被捕捉,也可以直接返回。

修改过滤器UsernamePasswordAuthenticationFilter(方法二)

准备一个过滤器,继承自UsernamePasswordAuthenticationFilter,在它的基础上,改一改就行了。


public class JsonFilter extends UsernamePasswordAuthenticationFilter {@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (!request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());} else {String contentType = request.getContentType();if (contentType.equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE) || contentType.equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) {//json请求String username = null;String password = null;try {User user = new ObjectMapper().readValue(request.getInputStream(), User.class);username = user.getUsername();username = username != null ? username.trim() : "";password = user.getPassword();password = password != null ? password : "";} catch (IOException e) {throw new RuntimeException(e);}UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username, password);this.setDetails(request, authRequest);return this.getAuthenticationManager().authenticate(authRequest);} else {//key -valuereturn super.attemptAuthentication(request, response);}}}
}

然后,配置一下。


@Configuration
public class SecurityConfig {@BeanJsonFilter jsonFilter(){JsonFilter jsonFilter = new JsonFilter();jsonFilter.setFilterProcessesUrl("/login");jsonFilter.setAuthenticationSuccessHandler(((request, response, authentication) -> {response.getWriter().write(authentication.getName());}));jsonFilter.setAuthenticationFailureHandler(((request, response, exception) -> {response.setContentType("text/html;charset=utf-8");response.getWriter().write(exception.getMessage());}));jsonFilter.setAuthenticationManager(authenticationManager());//配置Security的存储策略,如果我们没有定义jsonFilter,系统会给UsernamePasswordAuthenticationFilter设置SecurityContextRepository//这个说白了,就是,同一个会话的后续请求认证也要存上jsonFilter.setSecurityContextRepository(new HttpSessionSecurityContextRepository());return jsonFilter;}UserDetailsService userDetailsService(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("admin").password("{noop}123").build());return inMemoryUserDetailsManager;}@BeanAuthenticationManager authenticationManager(){DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService(userDetailsService());ProviderManager providerManager = new ProviderManager(daoAuthenticationProvider);return providerManager;}@BeanSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(a->a.anyRequest().authenticated())//.addFilter()  添加一个过滤器,但是自动排序,一般不用这个//添加一个过滤器,在某一个过滤器前面.addFilterBefore(jsonFilter(), UsernamePasswordAuthenticationFilter.class).csrf(c->c.disable());return http.build();}}

这样就ok了,同理,之前的验证码,也可以在这个过滤器里面实现的。

结语

生命不息,奋斗不止,加油!


http://www.ppmy.cn/embedded/21259.html

相关文章

23种设计模式之建造者模式

如何用建造者模式打造出独一无二的复杂对象 一、什么是建造者模式?1.1 建造者模式的定义1.2 建造者模式的优点1.3 建造者模式的缺点 二、 建造者模式的结构三、建造者模式的实现3.1 定义产品3.2 定义抽象建造者3.3 实现具体建造者类3.4 定义导演类3.5 定义Client &a…

STL——List常用接口模拟实现及其使用

认识list list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素…

水库大坝安全白蚁监测系统解决方案

一、系统背景 白蚁作为河岸生态系统中的重要病害,不仅会导致水库大坝外部环境发生改变,甚至会引发水库大坝破坏,进而导致自身结构失去稳定性,严重影响水库大坝的正常运行。因此,治理水库大坝白蚁是确保水库大坝工程顺利…

达梦(DM)数据库存储加密

达梦DM数据库存储加密 非透明加密CFALGORITHMSENCRYPTCFALGORITHMSDECRYPTSF_ENCRYPT_BINARYSF_DECRYPT_TO_BINARYSF_ENCRYPT_CHARSF_DECRYPT_TO_CHARSF_ENCRYPT_DATESF_DECRYPT_TO_DATESF_ENCRYPT_DATETIMESF_DECRYPT_TO_DATETIMESF_ENCRYPT_DECSF_DECRYPT_TO_DECSF_ENCRYPT_T…

新装电脑Flutter环境部署坑汇总(持续更新)

1.本地安装,安装fvm的坑 本人电脑使用windows ,安装fvm则一般使用choco安装,那么首先需要安装choco,打开powershell/或者cmd运行以下命令: Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager…

Hive判空函数 COALESCE 和 NVL 使用示例

Hive判空函数 COALESCE 和 NVL 使用示例 1. 在Hive中, COALESCE 和 NVL 函数都是用于处理NULL值的函数,以下是它们的用途总结: COALESCE: COALESCE 函数用于返回参数列表中第一个非NULL的数值或表达式。语法: COALESC…

浅识数据结构之时间复杂度

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。 P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。 文章目录 前言一. 时间复杂度1.1 时间复杂度的概念1.2 时间复杂度如何计算1.3 时间复杂度如何表…

IntelliJ IDEA 如何启用 JDK 预览特性

IntelliJ IDEA 也可以启用 JDK 的预览特性。 针对项目,选择项目结构。 配置是在语言结构上。 单击语言结构上的 SDK 默认,往下拉,就可以看到针对新版本的选项。 同时还可以看到那些版本是支持新特性预览的,那些版本是不支持新特…