SpringBoot20 集成SpringSecurity02 -> 利用SpringSecurity进行前后端分离的登录验证

1 SpirngBoot环境搭建

  创建一个SpringBoot项目即可,详情参见三少的相关博文

  参考博文 -> 点击前往

  SpirngBoot项目脚手架 -> 点击前往

2 引入SpirngSecurity依赖

  技巧01:引入了springSecurity相关依赖后,项目就会被SpringSecurity进行管理了;默认的登录名为user,登录密码会被打印到控制台上

  技巧02:SpringSecurity默认的配置使用的是

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

  2.1 启动项目

    技巧01:每次启动项目所打印出来的密码都是不一样的

    控制台打印的登录密码信息如下:

      

  2.2 请求一个后台实现的RestfulAPI

    技巧01:项目启动后,前台首次访问时都会被重定向到一个默认的登录页面

    技巧02:springSecurity默认的配置时使用表单进行登录

    技巧03:前后端分离时也是使用表单登录,而且表单的用户名必须是username,密码必须是password(PS: 前后端分离时只需要模拟出表单提交请求即可,即:请求路径对应,请求参数和后台对应即可)

      

  2.3 录入信息

    技巧01:如果用户名不是user或者密码不是控制台打印的信息,都不会通过验证

    技巧02:如果登录信息成功后,SpringSecurity会默认重定向到之前访问的路径

    技巧03:前后端分离时要求登录验证无论成功与否都是返回JSON格式的数据,具体怎么跳转有前端进行控制

      

3 SpirngSecurity基础配置

  技巧01:自定义SpringSecurity时需要重写一个UserDetaiService类,而该类需要使用一个对密码进行加密和解密的工具类,所以我们需要在自定义的SpringSecurity配置文件中指定这个密码加密解密工具的类的Bean,使得这个类会被Spring容器管理

package cn.test.demo.base_demo.config.springSecurity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

/**
 * @author 王杨帅
 * @create 2018-05-27 21:27
 * @desc
 **/
@Configuration
public class FurySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /** 依赖注入自定义的登录成功处理器 */
    @Autowired
    private FuryAuthenticationSuccessHandler furyAuthenticationSuccessHandler;

    /** 依赖注入自定义的登录失败处理器 */
    @Autowired
    private FuryAuthenticationFailureHandler furyAuthenticationFailureHandler;

//    向spring容器中创建一个Bean
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        http.formLogin()
//                .loginProcessingUrl("/login")
//                .successHandler(furyAuthenticationSuccessHandler)
//                .failureHandler(furyAuthenticationFailureHandler)
//                .and().authorizeRequests()
//                        .antMatchers("/login").permitAll()
//                        .anyRequest()
//                        .authenticated()
//                .and().csrf().disable();
//    }
}

  参考博文 -> 点击前往

   

4 继承UserDetaiService

  继承UserDetaiService的子类可以实现登录用户验证以及登录用户的权限查询

package cn.test.demo.base_demo.config.springSecurity;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * @author 王杨帅
 * @create 2018-05-27 21:23
 * @desc
 **/
@Component
@Slf4j
public class FuryUserDetailService implements UserDetailsService {

    /**
     * 依赖注入密码加密解密工具(PS: 需要在springsecurity的配置文件中配置这个Bean)
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        // 打印前端传过来的用户数据
        log.info("前端闯过来的用户名为:{}", username);

        // 模拟数据库中的数据
        String pwd = passwordEncoder.encode("111");

        // 返回一个User对象(技巧01:这个User对象的密码是从数据库中取出来的密码)
//      // 技巧02:数据库中的密码是在创建用户时将用户的密码利用SpreingSecurity配置中相同的密码加密解密工具加密过的
        return new User(username, pwd, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

  参考博文 -> 点击前往

  4.1 测试

    重启项目后,访问一个RestfulAPI时;控制台就不会再打印出密码信息了,继承UserDetaiService的子类会接收到前端传过来的用户名和密码,我们可以在继承UserDetaiService的子类中依赖注入先关的持久层来通过用户名到数据库中去查询用户密码,在将查到的密码和用户登录时的密码进行比对,从而判断用户登录验证是否成功;还可以根据用户名到数据库中去查询该用户的权限信息

    技巧01:此时用户名可以随便输入

    技巧02:由于密码是三少在后台进行硬编码的的,所以登录时密码必须是 “111”(即:用户名任意,密码只要是 111 就可以登录成功,否则就会登录失败)

6 前后端分离配置

  参考博文 -> 点击前往

  需求01:修改表单的登录路径

    》配置登录请求路径即可

  需求01:无论登录验证成功与否都返回JSON格式字符串

  技巧01:以上的需求都可以在自定义的SpringSecurity配置中实现

  技巧02:前后端分离时,请求的方式必须是POST方式,而且必须传递username和password两个变量到后台

  6.1 验证后的JSON格式返回

    只需要分别实现两个处理接口即可:AuthenticationSuccessHandler、AuthenticationFailureHandler;这两个接口分别处理登录验证成功和失败

package cn.test.demo.base_demo.config.springSecurity;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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;

/**
 * @author 王杨帅
 * @create 2018-05-27 21:48
 * @desc
 **/
@Slf4j
@Component
public class FuryAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private ObjectMapper objectMapper; // Json转化工具

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登录验证成功");
        response.setContentType("application/json;charset=UTF-8"); // 响应类型
        response.getWriter().write(objectMapper.writeValueAsString("登录验证成功"));
    }
}

FuryAuthenticationSuccessHandler.java

package cn.test.demo.base_demo.config.springSecurity;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 王杨帅
 * @create 2018-05-27 21:55
 * @desc
 **/
@Component
@Slf4j
public class FuryAuthenticationFailureHandler implements AuthenticationFailureHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        log.info("登录验证失败");
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(exception));;
    }
}

FuryAuthenticationFailureHandler.java

  6.2 配置自定SpringSecurity配置

package cn.test.demo.base_demo.config.springSecurity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

/**
 * @author 王杨帅
 * @create 2018-05-27 21:27
 * @desc
 **/
@Configuration
public class FurySpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /** 依赖注入自定义的登录成功处理器 */
    @Autowired
    private FuryAuthenticationSuccessHandler furyAuthenticationSuccessHandler;

    /** 依赖注入自定义的登录失败处理器 */
    @Autowired
    private FuryAuthenticationFailureHandler furyAuthenticationFailureHandler;

//    向spring容器中创建一个Bean
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginProcessingUrl("/furyLogin") // 登录请求路径
                .successHandler(furyAuthenticationSuccessHandler) // 验证成功处理器
                .failureHandler(furyAuthenticationFailureHandler) // 验证失败处理器
                .and().authorizeRequests()
                        .antMatchers("/furyLogin").permitAll() // 登录请求路径不进行过滤
                        .anyRequest()
                        .authenticated()
                .and().csrf().disable(); // 取消跨站请求伪造防护
    }

}

  6.3 测试

    利用postman进行测试

    技巧01:只需要模拟出 登录请求即可;POST请求,参数分别是username和password

    坑01:虽然在springSecurity的自定义配置文件中配置的登录请求路径是 /furyLogin ,但是我们在模拟的时候必须模拟 http://127.0.0.1:9999/dev/furyLogin,因为必须加上IP、端口和应用上下文路径

    6.3.1 登录验证失败的效果展示

      

    6.3.2 登录成功的效果

      

  案例源代码 -> 点击前往

7 利用Angular实现前端登录

8 登录成功后返回对应的菜单信息

9 权限问题

 

原文地址:https://www.cnblogs.com/NeverCtrl-C/p/9097947.html

时间: 2024-11-06 22:43:08

SpringBoot20 集成SpringSecurity02 -> 利用SpringSecurity进行前后端分离的登录验证的相关文章

SpringSecurity解决跨域问题,在SpringBoot整合SprinSecurity中如何用前后端分离Ajax登录,Ajax登录返回状态200还是近error

先说说SpringSecurity如何实现前后端分离Ajax登录? 今天使用SpringBoot整合SpringSecurity中想使用Ajax替代SpringSecurit的Form表单提交,在这里我们的提交方式还是使用表单提交 http.formLogin().loginProcessingUrl("/authentication/form") loginProcessingUrl方法表示你登录请求的地址,在这里SpringSecurity默认登录页面地址是/login ,填写了u

SpringSecurity实现前后端分离项目的登录认证

一.文章简介 本文简要介绍了spring security的基本原理和实现,并基于springboot整合了spring security实现了基于数据库管理的用户的登录和登出,登录过程实现了验证码的校验功能. 二.spring security框架简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.主要包括:用户认证(Authentication)和用户授权(Authorization)两个部分.用户认证指的是验证某个用户能

利用gulp解决前后端分离的header/footer引入问题

在我们进行前后端完全分离的时候,有一个问题一直是挺头疼的,那就是公共header和footer的引入.在传统利用后端渲染的情况下,我们可以把header.footer写成两个单独的模板,然后用后端语言的include即可在其他页面中引入.我之前在<一个简单粗暴的前后端分离方案>这篇文章中说过一种方法,就是用handlebars把header.footer模板预编译为js文件,然后在页面的头部用document.write写到页面中.这种方式的弊端也比较明显,那就是依赖一个模板引擎.在使用mvv

在前后端分离的SpringBoot项目中集成Shiro权限框架

项目背景 公司在几年前就采用了前后端分离的开发模式,前端所有请求都使用ajax.这样的项目结构在与CAS单点登录等权限管理框架集成时遇到了很多问题,使得权限部分的代码冗长丑陋,CAS的各种重定向也使得用户体验很差,在前端使用vue-router管理页面跳转时,问题更加尖锐.于是我就在寻找一个解决方案,这个方案应该对代码的侵入较少,开发速度快,实现优雅.最近无意中看到springboot与shiro框架集成的文章,在了解了springboot以及shiro的发展状况,并学习了使用方法后,开始在网上

django的crsf机制防御详解及在前后端分离中post数据到django-vue

django的crsf机制防御详解及在前后端分离中post数据到django 更新于: 2018-07-28 |  分类于 django CSRF(Cross Site Request Forgery) 跨站点伪造请求 某个用户已经登陆了你的网站,另外有一个恶意的网站有一个指向你网站的链接,那么当用户点击这个链接时,就会请求你的网站,但是你的网站以为是用户发来的请求,这时恶意网站就得逞了. django的应对措施 用户在post请求时,发送给用户一个token,然后在django内部实现了一个校

SpringBootSecurity学习(12)前后端分离版之简单登录

前后端分离 前面讨论了springboot下security很多常用的功能,其它的功能建议参考官方文档学习.网页版登录的形式现在已经不是最流行的了,最流行的是前后端分离的登录方式,前端单独成为一个项目,与后台的交互,包括登录认证和授权都是由异步接口来实现.在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高.这种应用模式比较适合纯网页应用, 但是当后端对接App时,App可能并不需要后端返回一个HTML网页,而

springboot shiro 前后端分离,解决跨域、过虑options请求、shiro管理session问题、模拟跨域请求

一.解决跨域.过虑options请求问题 1.创建过虑类 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; im

利用grunt-contrib-connect和grunt-connect-proxy搭建前后端分离的开发环境

前后端分离这个词一点都不新鲜,完全的前后端分离在岗位协作方面,前端不写任何后台,后台不写任何页面,双方通过接口传递数据完成软件的各个功能实现.此种情况下,前后端的项目都独立开发和独立部署,在开发期间有2个问题不可避免:第一是前端调用后台接口时的跨域问题(因为前后端分开部署):第二是前端脱离后台服务后无法独立运行.本文总结最近一个项目的工作经验,介绍利用grunt-contrib-connect和grunt-connect-proxy搭建前后端分离的开发环境的实践过程,希望能对你有所帮助. 注:

springboot2.0整合springsecurity前后端分离进行自定义权限控制

在阅读本文之前可以先看看springsecurity的基本执行流程,下面我展示一些核心配置文件,后面给出完整的整合代码到git上面,有兴趣的小伙伴可以下载进行研究 使用maven工程构建项目,首先需要引入最核心的依赖, <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <