Spring Security实现前后端分离Login登录功能,返回JSON提示,核心代码不到100行!

#前后端分离登录设计思路和流程图

  • 前后端分离是企业级应用开发的主流,登录功能同样采用前后端分离模式。
  • 用户信息存在数据库中。 
  • Spring Security提供身份认证。
  • 前后端交互通过JSON进行。
  • 登录成功不是页面跳转,而是一段JSON提示。

  

#第一步:前期准备工作

项目架构:

  • 开发环境Spring-boot 2.5.5
  • Maven
  • 数据库MySQL8.0+,存放用户、角色、用户角色对照表
  • 持久层Mybatis

数据库及表设计;MAVEN依赖;application.properties配置; 用户/角色实体类、持久层、用户服务类参考我的上一篇文章,这里不再重复讲述。

https://blog.csdn.net/m0_59562547/article/details/120864233

#第二步:WebSecurityJsonConfig核心配置类

  1. 首先注入UserService用于userDetailsService用户身份认证(包含密码、角色、锁定等)。
  2. 再配置用户登录密码需要BCryptPasswordEncoder密文认证。
  3. 再配置自定义登录参数loginid和passwd。
  4. successHandler为成功登陆后操作内容。这里我们获取当前登录用户主体信息principal,设置返回编码格式,将resp状态设置为200,将登录用户信息装入返回内容,并使用springboot自带的Jackson的objectMapper.writeValueAsString()方法将内容转化为JSON格式。
  5. failureHandler为登录失败后操作内容。这里我们设置返回编码格式,将resp状态设置为401,并根据exception类型输出返回内容,并转化为JSON格式。
  6. 最后我们设置所有接口不需要认证可访问,再关闭csrf。
package com.example.springsecurity.Config;
import com.example.springsecurity.Service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.*;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class WebSecurityJsonConfig extends WebSecurityConfigurerAdapter {
    //注入用户服务
    @Autowired
    UserService userService;
    //配置用户登录密码需要BCryptPasswordEncoder密文认证
    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder(10);
    }
    //基于数据库的用户账号密码、角色、过期、锁定等认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userService);
    }
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception{
        httpSecurity.authorizeRequests()
                .and()
                //开启表单登录,登录URL为/login
                .formLogin()
                .loginProcessingUrl("/login")
                //自定义登录参数用户名loginid密码passwd
                .usernameParameter("loginid")
                .passwordParameter("passwd")
                //身份认证成功,采用lambda写法,传入req,resp,auth参数
                .successHandler((request, response, authentication) -> {
                    //获取当前登录用户主体信息,包括用户名密码,角色,账号状态
                    Object principal = authentication.getPrincipal();
                    //设置返回编码格式,使用PrintWriter方法输出
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    //设置resp返回状态,成功为200
                    response.setStatus(200);
                    Map<String,Object> map =new HashMap<>();
                    //设置返回内容
                    map.put("status",200);
                    map.put("msg",principal);
                    //使用springboot自带的Jackson转化并输出JSON信息
                    ObjectMapper objectMapper=new ObjectMapper();
                    out.write(objectMapper.writeValueAsString(map));
                    out.flush();
                    out.close();
                })
                //身份认证失败,采用lambda写法,传入req,resp,exception参数
                .failureHandler((request, response, exception) -> {
                    //设置返回编码格式,使用PrintWriter方法输出
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    //设置resp返回状态,失败为401
                    response.setStatus(401);
                    Map<String,Object> map = new HashMap<>();
                    map.put("status",401);
                    //根据错误状态设置返回内容
                    if(exception instanceof LockedException){
                        map.put("msg","账户被锁定,登陆失败!");
                    }else if (exception instanceof BadCredentialsException){
                        map.put("msg","账户名或者密码输入错误,登录失败!");
                    }else if (exception instanceof DisabledException){
                        map.put("msg","账户被禁用,登陆失败!");
                    }else if(exception instanceof AccountExpiredException){
                        map.put("msg","账户已过期,登陆失败!");
                    }else if(exception instanceof CredentialsExpiredException){
                        map.put("msg","密码已过期,登陆失败!");
                    }else {
                        map.put("msg","登陆失败!");
                    }
                    //使用springboot自带的Jackson转化并输出JSON信息
                    ObjectMapper objectMapper =new ObjectMapper();
                    out.write(objectMapper.writeValueAsString(map));
                    out.flush();
                    out.close();
                })
                //接口不需要认证可以访问
                .permitAll()
                .and()
                //关闭csrf
                .csrf()
                .disable();
    }
}

#第三步:启动项目开始测试 

启动MySQL数据库和Spring-boot项目,使用POSTMAN进行测试,登录请求的用户名参数是loginid,密码是passwd,使用POST请求,登录成功后返回用户的基本信息(JSON格式)。

请求网址为http://localhost:8080/login?loginid=admin&passwd=007007,效果如下图:

密码错误,效果如下图:

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 Postman 发送请求时,需要注意以下几点: 1. 请求地址需要使用后端提供的登录接口地址。 2. 请求方式需要使用 POST 方法。 3. 请求头中需要添加 Content-Type: application/json。 4. 请求体中需要包含用户名和密码,格式为 JSON。 以下是使用 Java 发送登录请求的示例代码: ```java import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Scanner; public class Login { public static void main(String[] args) throws IOException { String username = "test"; String password = "test123"; String loginUrl = "http://localhost:8080/login"; String auth = username + ":" + password; String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8)); URL url = new URL(loginUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Authorization", "Basic " + encodedAuth); String requestBody = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}"; conn.setDoOutput(true); conn.getOutputStream().write(requestBody.getBytes(StandardCharsets.UTF_8)); Scanner scanner = new Scanner(conn.getInputStream()); while (scanner.hasNextLine()) { System.out.println(scanner.nextLine()); } scanner.close(); } } ``` 在发送请求时,需要将用户名和密码使用 Base64 编码后添加到请求头中的 Authorization 字段中。请求体中需要包含用户名和密码,格式为 JSON。在接收到响应后,可以使用 Scanner 将响应内容读取出来并打印。 注意:以上代码仅作为示例,实际使用时需要根据具体情况进修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值