前后端分离 SpringBoot + SpringSecurity 权限解决方案
发布日期:2021-06-30 16:51:06 浏览次数:3 分类:技术文章

本文共 12140 字,大约阅读时间需要 40 分钟。

一、前言

这里写图片描述

之前在团队里边做的项目的基于 session 的登录拦截,属于后端全栈式的开发的模式:

而公司这边都是前后端分离鲜明的,前端不要接触过多的业务逻辑,都由后端解决,基本思路是这样的:

服务端通过 JSON字符串,告诉前端用户有没有登录、认证,前端根据这些提示跳转对应的登录页、认证页等。

二、代码

代码已经放在github 上了:

温馨提示:这些代码都是通用的~~
这里写图片描述

下面给个示例,该自上述的之前的代码

1.AjaxResponseBody 给前端JSON的格式

返回给前端的数据格式

package com.cun.security3.bean;import java.io.Serializable;public class AjaxResponseBody implements Serializable{
private String status; private String msg; private Object result; private String jwtToken; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Object getResult() { return result; } public void setResult(Object result) { this.result = result; } public String getJwtToken() { return jwtToken; } public void setJwtToken(String jwtToken) { this.jwtToken = jwtToken; }}

2.AjaxAuthenticationEntryPoint 未登录

用户没有登录时返回给前端的数据

package com.cun.security3.config;import com.alibaba.fastjson.JSON;import com.cun.security3.bean.AjaxResponseBody;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.AuthenticationEntryPoint;import org.springframework.stereotype.Component;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@Componentpublic class AjaxAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { AjaxResponseBody responseBody = new AjaxResponseBody(); responseBody.setStatus("000"); responseBody.setMsg("Need Authorities!"); httpServletResponse.getWriter().write(JSON.toJSONString(responseBody)); }}

3.AjaxAuthenticationFailureHandler 登录失败

用户登录失败时返回给前端的数据

package com.cun.security3.config;import com.alibaba.fastjson.JSON;import com.cun.security3.bean.AjaxResponseBody;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;@Componentpublic class AjaxAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { AjaxResponseBody responseBody = new AjaxResponseBody(); responseBody.setStatus("400"); responseBody.setMsg("Login Failure!"); httpServletResponse.getWriter().write(JSON.toJSONString(responseBody)); }}

4.AjaxAuthenticationSuccessHandler 登录成功

用户登录成功时返回给前端的数据

package com.cun.security3.config;import com.alibaba.fastjson.JSON;import com.cun.security3.bean.AjaxResponseBody;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;@Componentpublic class AjaxAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { AjaxResponseBody responseBody = new AjaxResponseBody(); responseBody.setStatus("200"); responseBody.setMsg("Login Success!"); httpServletResponse.getWriter().write(JSON.toJSONString(responseBody)); }}

5.AjaxAccessDeniedHandler 无权访问

package com.cun.security3.config;import com.alibaba.fastjson.JSON;import com.cun.security3.bean.AjaxResponseBody;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.web.access.AccessDeniedHandler;import org.springframework.stereotype.Component;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@Componentpublic class AjaxAccessDeniedHandler implements AccessDeniedHandler {
@Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException { AjaxResponseBody responseBody = new AjaxResponseBody(); responseBody.setStatus("300"); responseBody.setMsg("Need Authorities!"); httpServletResponse.getWriter().write(JSON.toJSONString(responseBody)); }}

6.SpringSecurityConf 登录拦截全局配置

package com.cun.security3.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;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.config.http.SessionCreationPolicy;@Configurationpublic class SpringSecurityConf extends WebSecurityConfigurerAdapter {
@Autowired AjaxAuthenticationEntryPoint authenticationEntryPoint; // 未登陆时返回 JSON 格式的数据给前端(否则为 html) @Autowired AjaxAuthenticationSuccessHandler authenticationSuccessHandler; // 登录成功返回的 JSON 格式数据给前端(否则为 html) @Autowired AjaxAuthenticationFailureHandler authenticationFailureHandler; // 登录失败返回的 JSON 格式数据给前端(否则为 html) @Autowired AjaxLogoutSuccessHandler logoutSuccessHandler; // 注销成功返回的 JSON 格式数据给前端(否则为 登录时的 html) @Autowired AjaxAccessDeniedHandler accessDeniedHandler; // 无权访问返回的 JSON 格式数据给前端(否则为 403 html 页面) @Autowired SelfAuthenticationProvider provider; // 自定义安全认证 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 加入自定义的安全认证 auth.authenticationProvider(provider); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .httpBasic().authenticationEntryPoint(authenticationEntryPoint) .and() .authorizeRequests() .anyRequest() .authenticated()// 其他 url 需要身份认证 .and() .formLogin() //开启登录 .successHandler(authenticationSuccessHandler) // 登录成功 .failureHandler(authenticationFailureHandler) // 登录失败 .permitAll() .and() .logout() .logoutSuccessHandler(logoutSuccessHandler) .permitAll(); http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 无权访问 JSON 格式的数据 }}

7.SelfUserDetails 自定义 user 对象

package com.cun.security3.config;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import java.io.Serializable;import java.util.Collection;import java.util.Set;/** *  ① 定义 user 对象 */public class SelfUserDetails implements UserDetails, Serializable {
private String username; private String password; private Set
authorities; @Override public Collection
getAuthorities() { return this.authorities; } public void setAuthorities(Set
authorities) { this.authorities = authorities; } @Override public String getPassword() { // 最重点Ⅰ return this.password; } @Override public String getUsername() { // 最重点Ⅱ return this.username; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; }}

8.SelfUserDetailsService 用户认证、权限

package com.cun.security3.config;import org.springframework.security.authentication.encoding.Md5PasswordEncoder;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;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.bcrypt.BCryptPasswordEncoder;import org.springframework.stereotype.Component;import java.util.HashSet;import java.util.Set;/** *  ② 根据 username 获取数据库 user 信息 */@Componentpublic class SelfUserDetailsService implements UserDetailsService {
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //构建用户信息的逻辑(取数据库/LDAP等用户信息) SelfUserDetails userInfo = new SelfUserDetails(); userInfo.setUsername(username); // 任意用户名登录 Md5PasswordEncoder md5PasswordEncoder = new Md5PasswordEncoder(); String encodePassword = md5PasswordEncoder.encodePassword("123", username); // 模拟从数据库中获取的密码原为 123 userInfo.setPassword(encodePassword); Set authoritiesSet = new HashSet(); GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_ADMIN"); // 模拟从数据库中获取用户角色 authoritiesSet.add(authority); userInfo.setAuthorities(authoritiesSet); return userInfo; }}

9.SelfAuthenticationProvider 前端交互

package com.cun.security3.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.authentication.AuthenticationProvider;import org.springframework.security.authentication.BadCredentialsException;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.authentication.encoding.Md5PasswordEncoder;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.stereotype.Component;import java.util.HashSet;import java.util.Set;@Componentpublic class SelfAuthenticationProvider implements AuthenticationProvider {
@Autowired SelfUserDetailsService userDetailsService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String userName = (String) authentication.getPrincipal(); // 这个获取表单输入中返回的用户名; String password = (String) authentication.getCredentials(); // 这个是表单中输入的密码; Md5PasswordEncoder md5PasswordEncoder = new Md5PasswordEncoder(); String encodePwd = md5PasswordEncoder.encodePassword(password, userName); UserDetails userInfo = userDetailsService.loadUserByUsername(userName); if (!userInfo.getPassword().equals(encodePwd)) { throw new BadCredentialsException("用户名密码不正确,请重新登陆!"); } return new UsernamePasswordAuthenticationToken(userName, password, userInfo.getAuthorities()); } @Override public boolean supports(Class
authentication) { return true; }}

三、使用 postman 测试 ajax

1.未登录

这里写图片描述

2.登录失败

这里写图片描述

3.登录成功

这里写图片描述

4.注销成功

这里写图片描述

四、其他

温馨提示:session+cookie 不安全 ~

上述略有前后端分离的影子,真正前后端开发还要引入 JWT,有空再叙

后来还是写好了:
2018.7.18 更新:

转载地址:https://larger5.blog.csdn.net/article/details/81047869 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:前后端分离 SpringBoot + SpringSecurity + JWT + RBAC 实现用户无状态请求验证
下一篇:centos7 下将 Django2.0 项目部署到 阿里云 上(uwsgi3 +Nginx )

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月14日 10时30分33秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

tensorflow使用tensorboard进行可视化 2019-04-30
神经网络调参实战(二)—— activation & initializer & optimizer 2019-04-30
凸优化 convex optimization 2019-04-30
数据库索引 & 为什么要对数据库建立索引 / 数据库建立索引为什么会加快查询速度 2019-04-30
IEEE与APA引用格式 2019-04-30
research gap 2019-04-30
pytorch训练cifar10数据集查看各个种类图片的准确率 2019-04-30
Python鼠标点击图片,获取点击点的像素坐标 2019-04-30
路径规划(一) —— 环境描述(Grid Map & Feature Map) & 全局路径规划(最优路径规划(Dijkstra&A*star) & 概率路径规划(PRM&RRT)) 2019-04-30
神经网络调参实战(四)—— 加深网络层次 & 批归一化 batch normalization 2019-04-30
数据挖掘与数据分析(三)—— 探索性数据分析EDA(多因子与复合分析) & 可视化(1)—— 假设检验(μ&卡方检验&方差检验(F检验))&相关系数(皮尔逊&斯皮尔曼) 2019-04-30
RRT算法(快速拓展随机树)的Python实现 2019-04-30
路径规划(二) —— 轨迹优化(样条法) & 局部规划(人工势能场法) & 智能路径规划(生物启发(蚁群&RVO) & 强化学习) 2019-04-30
D*算法 2019-04-30
强化学习(四) —— Actor-Critic演员评论家 & code 2019-04-30
RESTful API 2019-04-30
优化算法(四)——粒子群优化算法(PSO) 2019-04-30
数据挖掘与数据分析(三)—— 探索性数据分析EDA(多因子与复合分析) & 可视化(2)——回归分析(最小二乘法&决定系数&残差不相关)&主成分分析&奇异值分解 2019-04-30
数据在Oracle中的存储 2019-04-30
优化算法(五)—人工蜂群算法Artificial Bee Colony Algorithm(ABC) 2019-04-30