Spring-Security 实现前后端分离登录
简述
使用Spring-Security来实现登录,但是搜到的都是通过模板引擎的方式来实现的,也就是必须通过login.html页面来登录。考虑到现在架构都是采用的是动静分离的架构,那么登录也需要使用纯Restful Api的方式来实现。
项目demo已经写好:
https://github.com/bulingfeng/spring-security-login.git
源码介绍
1、pom文件的引用
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
详细的引用包请查看git项目。
2、配置登录
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {private PasswordEncoder myPasswordEncoder;private CustomUserService myCustomUserService;private ObjectMapper objectMapper;public SecurityConfig(CustomUserService myCustomUserService, ObjectMapper objectMapper) {this.myPasswordEncoder =new BCryptPasswordEncoder();this.myCustomUserService = myCustomUserService;this.objectMapper = objectMapper;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authenticationProvider(authenticationProvider()).httpBasic()//未登录时,进行json格式的提示,很喜欢这种写法,不用单独写一个又一个的类.authenticationEntryPoint((request,response,authException) -> {response.setContentType("application/json;charset=utf-8");response.setStatus(HttpServletResponse.SC_FORBIDDEN);PrintWriter out = response.getWriter();Map<String,Object> map = new HashMap<String,Object>();map.put("code",403);map.put("message","未登录");out.write(objectMapper.writeValueAsString(map));out.flush();out.close();}).and().authorizeRequests().anyRequest().authenticated() //必须授权才能范围.and().formLogin() //使用自带的登录.permitAll()//登录失败,返回json.failureHandler((request,response,ex) -> {response.setContentType("application/json;charset=utf-8");response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);PrintWriter out = response.getWriter();Map<String,Object> map = new HashMap<String,Object>();map.put("code",401);if (ex instanceof UsernameNotFoundException || ex instanceof BadCredentialsException) {map.put("message","用户名或密码错误");} else if (ex instanceof DisabledException) {map.put("message","账户被禁用");} else {map.put("message","登录失败!");}out.write(objectMapper.writeValueAsString(map));out.flush();out.close();})//登录成功,返回json.successHandler((request,response,authentication) -> {Map<String,Object> map = new HashMap<String,Object>();map.put("code",200);map.put("message","登录成功");map.put("data",authentication);response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write(objectMapper.writeValueAsString(map));out.flush();out.close();}).and().exceptionHandling()//没有权限,返回json.accessDeniedHandler((request,response,ex) -> {response.setContentType("application/json;charset=utf-8");response.setStatus(HttpServletResponse.SC_FORBIDDEN);PrintWriter out = response.getWriter();Map<String,Object> map = new HashMap<String,Object>();map.put("code",403);map.put("message", "权限不足");out.write(objectMapper.writeValueAsString(map));out.flush();out.close();}).and().logout()//退出成功,返回json.logoutSuccessHandler((request,response,authentication) -> {Map<String,Object> map = new HashMap<String,Object>();map.put("code",200);map.put("message","退出成功");map.put("data",authentication);response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write(objectMapper.writeValueAsString(map));out.flush();out.close();}).permitAll();//开启跨域访问http.cors().disable();//开启模拟请求,比如API POST测试工具的测试,不开启时,API POST为报403错误http.csrf().disable();}@Overridepublic void configure(WebSecurity web) {//对于在header里面增加token等类似情况,放行所有OPTIONS请求。web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");}@Beanpublic AuthenticationProvider authenticationProvider() {DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();//对默认的UserDetailsService进行覆盖authenticationProvider.setUserDetailsService(myCustomUserService);authenticationProvider.setPasswordEncoder(myPasswordEncoder);return authenticationProvider;}}
3、查询用户信息
必须实现UserDetailsService#loadUserByUsername,这里只需使用用户名称查询用户信息即可,校验用户账号和密码的正确性都交给Spring-Security来实现即可。
/*** @Author:bulingfeng* @Date: 2020-06-13*/
@Component
@Slf4j
public class CustomUserService implements UserDetailsService {@Autowiredprivate SysUserDao userDao;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {SysUserPo po=userDao.selectUserByName2(username);return po;}
}
4、数据库代码
用户查询的接口
/*** @Author:bulingfeng* @Date: 2020-06-13*/
public interface SysUserDao extends BaseMapper<SysUserPo> {SysUserPo selectUserByName2(String userName);
}
Mybatis中配置查询
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bulingfeng.login.dao.SysUserDao"><select id="selectUserByName2" resultType="com.bulingfeng.login.entity.SysUserPo" parameterType="java.lang.String">selectid id,user_name userName,password password,role rolefromsys_userwhere user_name=#{userName}</select>
</mapper>
5、配置文件
server:port: 8080mybatis-plus:type-aliases-package: com.example.entitymapper-locations: classpath:/mapper/*Mapper.xmlspring:datasource:url: jdbc:mysql://127.0.0.1:3306/spring-boot-loginusername: rootpassword: mac666driver-class-name: com.mysql.jdbc.Driverlogging:level:root: debug
6、测试controller
/*** @Author:bulingfeng* @Date: 2020-08-21*/
@RestController
public class TestController {@GetMapping("/test")public String testApi(){return "success";}}
测试
1、启动服务器,然后调用测试接口:
127.0.0.1:8080/test
返回消息为:
{"code": 403,"message": "未登录"
}
2、使用账号和密码登录。(使用postman调用的方式必须为form-data表单的形式)
入参:username:root password:password。
如图所示:
返回结果:
{"code": 200,"data": {"authorities": [{"authority": "root"}],"details": {"remoteAddress": "127.0.0.1","sessionId": "240B9A8610686B534CFAC5BB7FA7D44A"},"authenticated": true,"principal": {"id": 1,"password": "$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG","role": "ROLE_ADMIN","authorities": [{"authority": "root"}],"username": "root","accountNonExpired": true,"accountNonLocked": true,"credentialsNonExpired": true,"enabled": true},"credentials": null,"name": "root"},"message": "登录成功"
}
这里第一次调用sessionId会为null,第二次以后会正常。此问题还没有修复。
3、再次调用测试接口
127.0.0.1:8080/test
返回参数:
success
总结
该项目实现了登陆,并且也实现了前后端的完全分离,从而前后端没有任何耦合性,所有接口都只有Http的方式来调用。从而实现完全解耦,这种方式的优势是可以后续如果是分布式部署的话,只需要实现session共享即可完成web项目的高可用。
后续会出一个关于session共享的博文和项目来描述。
查阅文档
https://www.jianshu.com/p/650a497b3a40
https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-storage-format
Spring-Security 实现前后端分离登录相关推荐
- Springboot + Spring Security 实现前后端分离登录认证及权限控制
Spring Security简介 Spring Security 是 Spring 家族中的一个安全管理框架,实际上,在 Spring Boot 出现之前,Spring Security 就已经发展 ...
- 新B站视频来了!Spring security + vue前后端分离后台管理系统
距离上次发布视频已经很久了哈,有点懒.这次发布的是一个基于Spring security + jwt + vue的前后端分离后台管理系统VueAdmin,项目讲解视频一共54集,共800分钟,发布到B ...
- Spring Boot+Vue/前后端分离/高并发/秒杀实战课程之spring Security快速搭建oauth2 内存版身份认证
Springboot快速搭建oauth2 内存版身份认证 环境准备 点击[Create New Project]创建一个新的项目 项目环境配置 配置Thymeleaf 搭建oauth2认证,加入两个依 ...
- 视频教程-SpringBoot+Security+Vue前后端分离开发权限管理系统-Java
SpringBoot+Security+Vue前后端分离开发权限管理系统 10多年互联网一线实战经验,现就职于大型知名互联网企业,架构师, 有丰富实战经验和企业面试经验:曾就职于某上市培训机构数年,独 ...
- phython在file同时写入两个_喜大普奔,两个开源的 Spring Boot + Vue 前后端分离项目可以在线体验了
折腾了一周的域名备案昨天终于搞定了. 松哥第一时间想到赶紧把微人事和 V 部落部署上去,我知道很多小伙伴已经等不及了. 1. 也曾经上过线 其实这两个项目当时刚做好的时候,我就把它们部署到服务器上了, ...
- spring boot+iview 前后端分离架构之用户管理的实现(三十)
spring boot 与 iview 前后端分离架构之用户管理的实现(三十) 公众号 用户管理 相关工具类的实现 User实体改造 UserOrg实体改造 UserRole实体改造 UserRole ...
- spring boot+iview 前后端分离架构之文件上传的实现(三十一)
spring boot 与 iview 前后端分离架构之文件上传的实现(三十一) 公众号 文件上传 前端改造 main.js引入配置的全局变量 编写baseImgUpload图片上传组件 baseIm ...
- Spring Boot + Vue 前后端分离开发,权限管理的一点思路
在传统的前后端不分的开发中,权限管理主要通过过滤器或者拦截器来进行(权限管理框架本身也是通过过滤器来实现功能),如果用户不具备某一个角色或者某一个权限,则无法访问某一个页面. 但是在前后端分离中,页面 ...
- Spring Boot2.x-13前后端分离的跨域问题解决方法之Nginx
文章目录 概述 浏览器同源策略 后台搭建 pom.xml interceptor 配置 Controller 启动测试 浏览器和session 后端工程发布到服务器上 问题复现 通过Nginx反向代理 ...
- Spring Boot + Vue 前后端分离开发,前端网络请求封装与配置
前端网络访问,主流方案就是 Ajax,Vue 也不例外,在 Vue2.0 之前,网络访问较多的采用 vue-resources,Vue2.0 之后,官方不再建议使用 vue-resources ,这个 ...
最新文章
- 中科院王飞跃:新的智能全球化将要来临,人工智能标准化为时尚早
- 应用语言学 计算机语言学,应用语言学的名词解释
- 用python数据分析excel多地天气_Python实现天气查询功能(外加Excel技巧)
- 毕业设计-计算机毕业设计-需求分析、概要设计、详细设计——我是这么写的(模板)
- Java加密方式(AES,DES,RSA,DSA,MD5)
- Java代码审计: ClassLoader应用
- Mac Os 安装配置Maven以及IntelliJ IDEA Maven使用
- 南阳oj S + T
- 数据结构与算法—队列详解
- 智能手表的下半场,机遇与挑战并存
- 高等数学笔记-苏德矿-第九章-重积分(Ⅱ)-三重积分
- SEO批量文章繁简转换,同义词替换
- 矩阵指数 matlab,空间计量-矩阵指数空间模型
- 为网站鼠标点击添加富强民主等内容Js代码
- 图的遍历 BFS遍历(深学思维)
- html多级列表不连续如何显示,完美解决word多级列表的编号不显示问题
- matplotlib·2(绘制饼图,直方图,极坐标图,复杂子区域分割)
- react-Mobx基本使用
- C++实现有理数类加减乘除
- 实物1操作:stc8a单片机和普通51/52单片机的异同以及下载步骤(点亮一盏LED为例)
热门文章
- 一文全面了解光纤连接器
- 计算机组成原理实验脱机运算器,计算机组成原理实验1_脱机运算器
- 用python测测你身体是否健康
- oracle expense po,ORACLE ERP中PO/INV/AP/GL流程对应那些关键基表、接口表?
- Armin Strom推出“致敬1”系列;卡西欧将发布紧凑型G-SHOCK | 知消
- Windows笔记本声音无法找到输出设备
- ERROR 2003 ( HY000 ) : Can ‘t connect to MySQL server on ‘ xxx.xxx.xxx.xxx ‘,
- WinSCP连接不上虚拟机
- D19:Duplicate Number(重复数字,翻译+题解)
- 有了这台冰箱,想在家宅多久都可以