简述

使用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 实现前后端分离登录相关推荐

  1. Springboot + Spring Security 实现前后端分离登录认证及权限控制

    Spring Security简介 Spring Security 是 Spring 家族中的一个安全管理框架,实际上,在 Spring Boot 出现之前,Spring Security 就已经发展 ...

  2. 新B站视频来了!Spring security + vue前后端分离后台管理系统

    距离上次发布视频已经很久了哈,有点懒.这次发布的是一个基于Spring security + jwt + vue的前后端分离后台管理系统VueAdmin,项目讲解视频一共54集,共800分钟,发布到B ...

  3. Spring Boot+Vue/前后端分离/高并发/秒杀实战课程之spring Security快速搭建oauth2 内存版身份认证

    Springboot快速搭建oauth2 内存版身份认证 环境准备 点击[Create New Project]创建一个新的项目 项目环境配置 配置Thymeleaf 搭建oauth2认证,加入两个依 ...

  4. 视频教程-SpringBoot+Security+Vue前后端分离开发权限管理系统-Java

    SpringBoot+Security+Vue前后端分离开发权限管理系统 10多年互联网一线实战经验,现就职于大型知名互联网企业,架构师, 有丰富实战经验和企业面试经验:曾就职于某上市培训机构数年,独 ...

  5. phython在file同时写入两个_喜大普奔,两个开源的 Spring Boot + Vue 前后端分离项目可以在线体验了

    折腾了一周的域名备案昨天终于搞定了. 松哥第一时间想到赶紧把微人事和 V 部落部署上去,我知道很多小伙伴已经等不及了. 1. 也曾经上过线 其实这两个项目当时刚做好的时候,我就把它们部署到服务器上了, ...

  6. spring boot+iview 前后端分离架构之用户管理的实现(三十)

    spring boot 与 iview 前后端分离架构之用户管理的实现(三十) 公众号 用户管理 相关工具类的实现 User实体改造 UserOrg实体改造 UserRole实体改造 UserRole ...

  7. spring boot+iview 前后端分离架构之文件上传的实现(三十一)

    spring boot 与 iview 前后端分离架构之文件上传的实现(三十一) 公众号 文件上传 前端改造 main.js引入配置的全局变量 编写baseImgUpload图片上传组件 baseIm ...

  8. Spring Boot + Vue 前后端分离开发,权限管理的一点思路

    在传统的前后端不分的开发中,权限管理主要通过过滤器或者拦截器来进行(权限管理框架本身也是通过过滤器来实现功能),如果用户不具备某一个角色或者某一个权限,则无法访问某一个页面. 但是在前后端分离中,页面 ...

  9. Spring Boot2.x-13前后端分离的跨域问题解决方法之Nginx

    文章目录 概述 浏览器同源策略 后台搭建 pom.xml interceptor 配置 Controller 启动测试 浏览器和session 后端工程发布到服务器上 问题复现 通过Nginx反向代理 ...

  10. Spring Boot + Vue 前后端分离开发,前端网络请求封装与配置

    前端网络访问,主流方案就是 Ajax,Vue 也不例外,在 Vue2.0 之前,网络访问较多的采用 vue-resources,Vue2.0 之后,官方不再建议使用 vue-resources ,这个 ...

最新文章

  1. 中科院王飞跃:新的智能全球化将要来临,人工智能标准化为时尚早
  2. 应用语言学 计算机语言学,应用语言学的名词解释
  3. 用python数据分析excel多地天气_Python实现天气查询功能(外加Excel技巧)
  4. 毕业设计-计算机毕业设计-需求分析、概要设计、详细设计——我是这么写的(模板)
  5. Java加密方式(AES,DES,RSA,DSA,MD5)
  6. Java代码审计: ClassLoader应用
  7. Mac Os 安装配置Maven以及IntelliJ IDEA Maven使用
  8. 南阳oj S + T
  9. 数据结构与算法—队列详解
  10. 智能手表的下半场,机遇与挑战并存
  11. 高等数学笔记-苏德矿-第九章-重积分(Ⅱ)-三重积分
  12. SEO批量文章繁简转换,同义词替换
  13. 矩阵指数 matlab,空间计量-矩阵指数空间模型
  14. 为网站鼠标点击添加富强民主等内容Js代码
  15. 图的遍历 BFS遍历(深学思维)
  16. html多级列表不连续如何显示,完美解决word多级列表的编号不显示问题
  17. matplotlib·2(绘制饼图,直方图,极坐标图,复杂子区域分割)
  18. react-Mobx基本使用
  19. C++实现有理数类加减乘除
  20. 实物1操作:stc8a单片机和普通51/52单片机的异同以及下载步骤(点亮一盏LED为例)

热门文章

  1. 一文全面了解光纤连接器
  2. 计算机组成原理实验脱机运算器,计算机组成原理实验1_脱机运算器
  3. 用python测测你身体是否健康
  4. oracle expense po,ORACLE ERP中PO/INV/AP/GL流程对应那些关键基表、接口表?
  5. Armin Strom推出“致敬1”系列;卡西欧将发布紧凑型G-SHOCK | 知消
  6. Windows笔记本声音无法找到输出设备
  7. ERROR 2003 ( HY000 ) : Can ‘t connect to MySQL server on ‘ xxx.xxx.xxx.xxx ‘,
  8. WinSCP连接不上虚拟机
  9. D19:Duplicate Number(重复数字,翻译+题解)
  10. 有了这台冰箱,想在家宅多久都可以