SpringSecurity(二)获取JSON格式的用户名密码

SpringSecurity环境

pom.xml

pom.xml依赖

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

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

		<!-- SpringSecurity的依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.70</version>
		</dependency>
	

自定义获取用户名和密码

SpringSecurity自带的方式

UsernamePasswordAuthenticationFilter.java 这个类是处理身份验证表单提交
其中的方法 attemptAuthentication(HttpServletRequest request, HttpServletResponse response) 就是获取用户名和密码的方法

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		if (this.postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}
		String username = obtainUsername(request);
		username = (username != null) ? username : "";
		username = username.trim();
		String password = obtainPassword(request);
		password = (password != null) ? password : "";
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}

其中有两个方法obtainPassword(),obtainUsername()这就是SpringSecurity获取用户名和密码的方法

@Nullable
	protected String obtainPassword(HttpServletRequest request) {
		return request.getParameter(this.passwordParameter);
	}
@Nullable
	protected String obtainUsername(HttpServletRequest request) {
		return request.getParameter(this.usernameParameter);
	}

可以发现默认的是获取param里的内容,如果是JSON格式的用户名和密码的话是无法获取的,之后我们可以用一个类继承 UsernamePasswordAuthenticationFilter 并重写其中的 attemptAuthentication 方法 获取JSON格式的用户名和密码,你也可重写obtainPassword,obtainUsername这两个方法达成同样的目的。

自定义获取用户名密码的方式

获取JSON格式的用户名密码

新建MyUsernamePasswordAuthenticationFilter继承UsernamePasswordAuthenticationFilter
重写attemptAuthentication方法

public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String username = null;
        String password = null;
        try {
            JSONObject jsonObject = JsonUtils.getRequestJsonObject(request);
            System.out.println(jsonObject);
            username = String.valueOf(jsonObject.get("username"));
            password = String.valueOf(jsonObject.get("password"));
            username = (username != null) ? username : "";
            password = (password != null) ? password : "";
        } catch (IOException e) {
            e.printStackTrace();
        }
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

在SecurityConfiguration中配置他

    @Bean
    public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
        UsernamePasswordAuthenticationFilter filter = new MyUsernamePasswordAuthenticationFilter();
        //这里设置自带的AuthenticationManager,否则要自己写一个
        filter.setAuthenticationManager(authenticationManagerBean());
        //设置处理成功处理器
        filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                response.setContentType("application/json;charset=UTF-8");
                String message = "登录成功";
                PrintWriter printWriter = response.getWriter();
                printWriter.write(message);
                printWriter.flush();
                printWriter.close();
            }
        });
        //设置过滤器拦截路径
        filter.setFilterProcessesUrl("/newlogin");
        return filter;
    }


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

我们使用postmen测试 http://localhost:8080/newlogin

在这里插入图片描述

这里解释一下为什么这么配置

先看一下不自定义的配置

.and()
                //开启登录
                .formLogin()
                //登录页面路径
                .loginPage("/toLogin")
                //执行登录的路径
                .loginProcessingUrl("/login")
                //登录成功后转发页面
                .successForwardUrl("/index")
                //.successHandler()
                .permitAll()
         

这里的 .loginProcessingUrl("/login")在源码中是调用setRequiresAuthenticationRequestMatcher 方法

	public T loginProcessingUrl(String loginProcessingUrl) {
		this.loginProcessingUrl = loginProcessingUrl;
		this.authFilter.setRequiresAuthenticationRequestMatcher(createLoginProcessingUrlMatcher(loginProcessingUrl));
		return getSelf();
	}

最后实际上调用的是下面的第二个方法
自定义过滤器中 filter.setFilterProcessesUrl("/newlogin") 最后调用的是第一方法然后调用第二个方法,也就是可以说等于 .loginProcessingUrl("/login")

	public void setFilterProcessesUrl(String filterProcessesUrl) {
		setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(filterProcessesUrl));
	}

	public final void setRequiresAuthenticationRequestMatcher(RequestMatcher requestMatcher) {
		Assert.notNull(requestMatcher, "requestMatcher cannot be null");
		this.requiresAuthenticationRequestMatcher = requestMatcher;
	}

也就是说我们配置 filter.setFilterProcessesUrl("/newlogin") 就是在配置 .loginProcessingUrl("/login")
只不过 filter.setFilterProcessesUrl("/newlogin")是在配置我们自定义的过滤器,而 .loginProcessingUrl("/login")是在配置自带的过滤器。实际是在进行同样配置操作。

这里.successForwardUrl("/index")和.successHandler()这个被我注释掉了,在源码中也是差不多的操作

	public FormLoginConfigurer<H> successForwardUrl(String forwardUrl) {
		successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
		return this;
	}
	public final T successHandler(AuthenticationSuccessHandler successHandler) {
		this.successHandler = successHandler;
		return getSelf();
	}

通过上面代码我们可以看出.successForwardUrl("/index")实际上就是调用了successHandler(),只不过用了一个ForwardAuthenticationSuccessHandler封装了一下。
再看看我们对自定义过滤器的配置一下就明白了

//设置处理成功处理器
        filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                response.setContentType("application/json;charset=UTF-8");
                String message = "登录成功";
                PrintWriter printWriter = response.getWriter();
                printWriter.write(message);
                printWriter.flush();
                printWriter.close();
            }
        });

漏了一个配置这里补一下,配置在configure(HttpSecurity http)方法中的。

		//在UsernamePasswordAuthenticationFilter之前调用我们自定义的过滤器
        http.addFilterAt(usernamePasswordAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);

举一反三我们可以有更多的设置

登出成功处理器

 .and()
                //开启登出
                .logout()
                //执行登出路径
                .logoutUrl("/logout")
                //登出成功后转发页面
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.setContentType("application/json;charset=UTF-8");
                        String message = "登出成功";
                        PrintWriter printWriter = response.getWriter();
                        printWriter.write(message);
                        printWriter.flush();
                        printWriter.close();
                    }
                })

登陆成功和失败处理器

    @Bean
    public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
        UsernamePasswordAuthenticationFilter filter = new MyUsernamePasswordAuthenticationFilter();

        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                response.setContentType("application/json;charset=UTF-8");
                String message = "登录成功";
                PrintWriter printWriter = response.getWriter();
                printWriter.write(message);
                printWriter.flush();
                printWriter.close();
            }
        });
        filter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
            @Override
            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                response.setContentType("application/json;charset=UTF-8");
                String message = "登录失败";
                PrintWriter printWriter = response.getWriter();
                printWriter.write(message);
                printWriter.flush();
                printWriter.close();
            }
        });
        filter.setFilterProcessesUrl("/newlogin");
        return filter;
    }
    

未登录账号处理

http.addFilterAt(usernamePasswordAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
        .exceptionHandling()
        .authenticationEntryPoint(new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                response.setContentType("application/json;charset=UTF-8");
                String message = "请先进行登录";
                PrintWriter printWriter = response.getWriter();
                printWriter.write(message);
                printWriter.flush();
                printWriter.close();
            }
        })
        ;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 前后端分离是一种将前端界面与后端逻辑进行分离开发的架构方式,使得前端与后端可以并行开发。OAuth 2.0是一种授权框架,用于授权和认证流程的规范化,而Spring Security是一个在Java实现安全控制的框架,提供了大量的安全特性。Spring Authorization Server是Spring Security用于实现授权服务器的模块,它支持OAuth 2.0的各种授权模式。 密码模式是OAuth 2.0的一种授权模式,它允许用户通过提交用户名密码获取访问令牌,然后使用该令牌来访问受保护的资源。在前后端分离的架构,可以使用Spring Security配合Spring Authorization Server来实现密码模式的认证和授权。 在密码模式下,前端首先需要收集用户的用户名密码,并将其发送给后端。后端使用Spring Security提供的密码编码器对密码进行加密,并验证用户名密码的正确性。如果验证通过,则后端向客户端颁发一个访问令牌,通常是一个JWT(JSON Web Token)。前端使用获得的访问令牌来访问需要受保护的资源,每次请求将该令牌作为Authorization头的Bearer字段发送给后端进行验证。后端可以使用Spring Security的资源服务器来验证该令牌的有效性,并根据用户的权限控制对资源的访问。 使用Spring SecuritySpring Authorization Server的密码模式可以实现安全的前后端分离架构。通过合理配置和使用安全特性,可以保障用户的身份认证和资源的授权,确保系统的安全性。 ### 回答2: 前后端分离是一种软件架构模式,前端和后端通过使用API进行通信,分别负责处理用户界面和数据逻辑。OAuth 2.0是一种用于授权的开放标准协议,它允许用户在第三方应用程序授权访问其受保护的资源。Spring SecuritySpring框架的一个模块,提供了身份验证和授权功能。 在前后端分离的架构,前端应用程序通常需要使用OAuth 2.0协议进行用户授权,以访问后端应用程序的受保护资源。为了实现密码模式,我们可以使用Spring Security的模块之一,即spring-authorization-server。 spring-authorization-server是Spring Security的一个子模块,用于实现OAuth 2.0协议的授权服务器。密码模式是OAuth 2.0协议的一种授权模式,允许前端应用程序通过用户的用户名密码进行授权。密码模式在安全性上有一定的风险,因此在实际应用需要谨慎使用。 使用spring-authorization-server的密码模式,我们可以在前端应用程序收集用户的用户名密码,并将其提交给后端应用程序进行验证。后端应用程序将使用Spring Security进行身份验证,并向前端应用程序颁发一个访问令牌,该令牌可以用于后续的API请求。 通过使用前后端分离、OAuth 2.0和spring-authorization-server的密码模式,我们可以实现安全的用户授权和身份验证机制,确保只有经过授权的用户才能访问受保护的资源。这种架构模式能够提高系统的安全性和可扩展性,适用于各种类型的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值