当前位置:   article > 正文

SpringbootSecurity登陆验证(前后端分离)_springsecurity前后端分验证码登录

springsecurity前后端分验证码登录

一、什么是jwt

JWT全称是JSON Web Token,如果从字面上理解感觉是基于JSON格式用于网络传输的令牌。实际上,JWT是一种紧凑的Claims声明格式,旨在用于空间受限的环境进行传输,常见的场景如HTTP授权请求头参数和URI查询参数。JWT会把Claims转换成JSON格式,而这个JSON内容将会应用为JWS结构的有效载荷或者应用为JWE结构的(加密处理后的)原始字符串,通过消息认证码(Message Authentication Code或者简称MAC)和/或者加密操作对Claims进行数字签名或者完整性保护。

二、创建后端项目

2.1 添加pom依赖

  1. <!-- hutool 依赖 -->
  2. <dependency>
  3. <groupId>cn.hutool</groupId>
  4. <artifactId>hutool-all</artifactId>
  5. <version>5.8.16</version>
  6. </dependency>

2.2 编辑entity、mapper、service、controller

这里就不过多写了,依旧是跟上一边的文章一样

2.3 JWT 过滤器类

  1. package com.aaa.filter;
  2. import cn.hutool.jwt.JWT;
  3. import cn.hutool.jwt.JWTUtil;
  4. import com.aaa.until.ResponseMsg;
  5. import com.fasterxml.jackson.databind.ObjectMapper;
  6. import org.apache.commons.lang3.ArrayUtils;
  7. import org.apache.commons.lang3.StringUtils;
  8. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  9. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  10. import org.springframework.security.core.context.SecurityContextHolder;
  11. import org.springframework.stereotype.Component;
  12. import org.springframework.web.filter.OncePerRequestFilter;
  13. import javax.servlet.FilterChain;
  14. import javax.servlet.ServletException;
  15. import javax.servlet.http.HttpServletRequest;
  16. import javax.servlet.http.HttpServletResponse;
  17. import java.io.IOException;
  18. import java.io.PrintWriter;
  19. import java.util.List;
  20. import java.util.stream.Collectors;
  21. @Component
  22. public class JWTFilter extends OncePerRequestFilter {
  23. /**
  24. * 重写的doFilterInternal方法
  25. * 解析token并验证用户信息
  26. * 如果验证成功,则保存用户信息并放行
  27. * 如果验证失败,则返回错误信息
  28. * 如果token为空且请求路径不在白名单中,则返回错误信息
  29. */
  30. @Override
  31. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
  32. // 白名单路径
  33. String[] whitename = {"/login"};
  34. // 获取请求头中的token
  35. String token = request.getHeader("token");
  36. // 如果token不为空
  37. if (StringUtils.isNotBlank(token)) {
  38. // 验证token是否有效
  39. boolean verify = JWTUtil.verify(token, "user".getBytes());
  40. // 如果验证通过
  41. if (verify) {
  42. // 解析token,获取用户名和资源信息
  43. JWT jwt = JWTUtil.parseToken(token);
  44. String username = (String) jwt.getPayload("username");
  45. List<String> resources = (List<String>) jwt.getPayload("resources");
  46. // 将资源信息转换为SimpleGrantedAuthority列表
  47. List<SimpleGrantedAuthority> resourceList = resources.stream().map(res -> new SimpleGrantedAuthority(res)).collect(Collectors.toList());
  48. // 保存用户信息
  49. UsernamePasswordAuthenticationToken userPwdToken = new UsernamePasswordAuthenticationToken(username, null, resourceList);
  50. SecurityContextHolder.getContext().setAuthentication(userPwdToken);
  51. // 放行
  52. filterChain.doFilter(request, response);
  53. } else {
  54. // 验证失败,返回错误信息
  55. ResponseMsg responseMsg = new ResponseMsg(401, "没有登陆", null);
  56. printJsonData(response, responseMsg);
  57. }
  58. } else {
  59. // 如果token为空,检查请求路径是否在白名单中
  60. String requestURI = request.getRequestURI();
  61. // 如果在白名单中,放行
  62. if (ArrayUtils.contains(whitename, requestURI)) {
  63. filterChain.doFilter(request, response);
  64. } else {
  65. // 如果不在白名单中,返回错误信息
  66. ResponseMsg responseMsg = new ResponseMsg(401, "没有登陆", null);
  67. printJsonData(response, responseMsg);
  68. }
  69. }
  70. }
  71. public void printJsonData(HttpServletResponse response, ResponseMsg responseMsg) {
  72. try {
  73. response.setContentType("application/json;charset=utf8"); // 设置响应内容类型为JSON,并指定编码为UTF-8
  74. ObjectMapper objectMapper = new ObjectMapper();
  75. String json = objectMapper.writeValueAsString(responseMsg); // 使用ObjectMapper将ResponseMsg对象转化为JSON字符串
  76. PrintWriter writer = response.getWriter();
  77. writer.print(json); // 将JSON字符串写入响应输出流
  78. writer.flush();//刷新
  79. writer.close();//关闭
  80. } catch (Exception e) {
  81. e.printStackTrace(); // 打印异常堆栈信息
  82. }
  83. }
  84. }

2.4 跨域配置CrossConfig

  1. package com.aaa.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.cors.CorsConfiguration;
  5. import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
  6. import org.springframework.web.filter.CorsFilter;
  7. @Configuration
  8. public class CrossConfig {
  9. @Bean
  10. public CorsFilter corsFilter() {
  11. final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  12. final CorsConfiguration corsConfiguration = new CorsConfiguration();
  13. //corsConfiguration.setAllowCredentials(true);允许携带cookie
  14. corsConfiguration.addAllowedHeader("*"); // 允许所有的头
  15. corsConfiguration.addAllowedOrigin("*"); // 允许所有的请求源
  16. corsConfiguration.addAllowedMethod("*"); // 所欲的方法 get post delete put
  17. source.registerCorsConfiguration("/**", corsConfiguration); // 所有的路径都允许跨域
  18. return new CorsFilter(source);
  19. }
  20. }

2.5 SecurityConfig 配置类

  1. package com.aaa.config;
  2. import cn.hutool.jwt.JWTUtil;
  3. import com.aaa.filter.JWTFilter;
  4. import com.aaa.until.ResponseMsg;
  5. import com.fasterxml.jackson.databind.ObjectMapper;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  9. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  10. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  11. import org.springframework.security.core.GrantedAuthority;
  12. import org.springframework.security.core.userdetails.UserDetailsService;
  13. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  14. import org.springframework.security.crypto.password.PasswordEncoder;
  15. import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  16. import javax.annotation.Resource;
  17. import javax.servlet.http.HttpServletResponse;
  18. import java.io.PrintWriter;
  19. import java.util.Collection;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.stream.Collectors;
  24. @Configuration
  25. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  26. @Resource
  27. protected UserDetailsService userDetailsService;
  28. @Bean
  29. public PasswordEncoder passwordEncoder(){
  30. return new BCryptPasswordEncoder();
  31. }
  32. @Resource
  33. public JWTFilter jwtFilter;
  34. @Override
  35. protected void configure(HttpSecurity http) throws Exception {
  36. //.usernameParameter("username")//登陆账号
  37. //.passwordParameter("userpassword");//登陆密码
  38. //.defaultSuccessUrl("/test");//登陆成功的跳转路径
  39. // 配置登录页面和登录处理路径
  40. http.formLogin().loginPage("/login.html")//路径前面必须加 /
  41. .loginProcessingUrl("/login")//跟提交的路径一样
  42. // 登录成功的处理逻辑
  43. .successHandler((request, response, authentication) ->{
  44. Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();//获取资源信息
  45. List<String> resources = authorities.stream().map(auth -> auth.getAuthority()).collect(Collectors.toList());//转为stream流变成list
  46. Map map = new HashMap<>();
  47. map.put("username",authentication.getName());
  48. map.put("resources",resources);
  49. //生成token
  50. String token = JWTUtil.createToken(map, "user".getBytes());
  51. ResponseMsg responseMsg = new ResponseMsg(200,"登陆成功",token);
  52. //响应返回信息
  53. printJsonData(response,responseMsg);
  54. })
  55. // 登录失败的处理逻辑
  56. .failureHandler((request, response, exception)->{
  57. ResponseMsg responseMsg = new ResponseMsg(400,"验证失败");
  58. printJsonData(response,responseMsg);
  59. });
  60. // 配置权限不允许的处理逻辑
  61. http.exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> {
  62. ResponseMsg responseMsg = new ResponseMsg(403,"权限不允许",null);
  63. printJsonData(response,responseMsg);
  64. });
  65. // 配置不需要验证的路径
  66. http.authorizeRequests().antMatchers("/login.html", "login").permitAll();//不用验证
  67. //http.authorizeRequests().antMatchers("/test").hasRole("test");//必须有哪个权限才能访问
  68. //http.authorizeRequests().antMatchers("/test").hasAnyAuthority("resource");//必须有哪个资源才能访问
  69. // 配置其他路径需要验证
  70. http.authorizeRequests().anyRequest().authenticated();
  71. // 添加JWT过滤器
  72. http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
  73. //关闭csrf保护
  74. http.csrf().disable();
  75. // 配置跨域
  76. http.cors();
  77. }
  78. @Override
  79. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  80. auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
  81. }
  82. public void printJsonData(HttpServletResponse response, ResponseMsg responseMsg) {
  83. try {
  84. response.setContentType("application/json;charset=utf8"); // json格式 编码是中文
  85. ObjectMapper objectMapper = new ObjectMapper();
  86. String s = objectMapper.writeValueAsString(responseMsg);// 使用ObjectMapper将result转化json为字符串
  87. PrintWriter writer = response.getWriter();
  88. writer.print(s);
  89. writer.flush();
  90. writer.close();
  91. }catch (Exception e){
  92. e.printStackTrace();
  93. }
  94. }
  95. }

2.6 SecurityService类

也是跟上一篇的笔记一样

三、创建前端vue项目

login页面

不要忘了在路由下添加login页面

  1. <template>
  2. <div>
  3. <el-form style="width: 400px ;margin: auto auto" :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
  4. <el-form-item label="名字" prop="username">
  5. <el-input type="text" v-model="ruleForm.username" autocomplete="off"></el-input>
  6. </el-form-item>
  7. <el-form-item label="密码" prop="password">
  8. <el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
  9. </el-form-item>
  10. <el-form-item>
  11. <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
  12. <el-button @click="resetForm('ruleForm')">重置</el-button>
  13. </el-form-item>
  14. </el-form>
  15. </div>
  16. </template>
  17. <script>
  18. import qs from 'qs';
  19. export default {
  20. data() {
  21. return {
  22. ruleForm: {
  23. username: 'user000',//每次刷新页面都要重新输入账号密码,所以直接把账号密码写入进来了
  24. password: '123456',
  25. },
  26. rules: {
  27. username: [
  28. {required: true, message: '请输入账户', trigger: 'blur'}
  29. ],
  30. password: [
  31. {required: true, message: '请输入密码', trigger: 'blur'}
  32. ]
  33. }
  34. };
  35. },
  36. methods: {
  37. submitForm(formName) {
  38. this.$refs[formName].validate((valid) => {
  39. if (valid) {
  40. alert('验证成功,准备提交')
  41. this.$axios.post('/login',qs.stringify(this.ruleForm)).then(res=>{
  42. console.log(res)
  43. if (res.data.code == 200){
  44. console.log(res.data.data);
  45. //--------------------------------------------------------------
  46. sessionStorage.setItem("token",res.data.data)在sessionstorage中添加一个为token的数据
  47. //--------------------------------------------------------------
  48. location.href='/main';//成功访问main页面
  49. }else {
  50. }
  51. })
  52. //location.href='/main'
  53. } else {
  54. alert('验证失败');
  55. return false;
  56. }
  57. });
  58. },
  59. resetForm(formName) {
  60. this.$refs[formName].resetFields();
  61. }
  62. }
  63. }
  64. </script>

在main.js添加下面的代码

验证token是否存在,如果有的话就在请求头里面添加token

  1. // 请求拦截器
  2. instance.interceptors.request.use(config => {
  3. if (sessionStorage.getItem("token")){
  4. let token = sessionStorage.getItem("token");
  5. config.headers['token'] = token;
  6. }
  7. return config;
  8. }, error => {
  9. return Promise.reject(error);
  10. });

四、总结

从前端页面输入账号向后端发送跨域请求,后端接受参数验证是否在数据库中存在,如果存在就去把用户在数据库中的角色权限和资源权限查出来,保存在Security中.登陆成功后就把用户的信息用JWTUtil.createToken()方法生成token,返回给前端,前端拿到token,前端再次向后端发起请求时携带token,后端识别,如果正确的话就放行,不正确就访问失败

 
 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号