前后端分离 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2024年04月14日 10时30分33秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
tensorflow使用tensorboard进行可视化
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
RRT算法(快速拓展随机树)的Python实现
2019-04-30
D*算法
2019-04-30
强化学习(四) —— Actor-Critic演员评论家 & code
2019-04-30
RESTful API
2019-04-30
优化算法(四)——粒子群优化算法(PSO)
2019-04-30
数据在Oracle中的存储
2019-04-30