SpringSecurity结合电商项目

pom

<!--SpringSecurity及JWT依赖配置-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</ artifactId></dependency>
<!--Hutool Java工具包-->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>4.5.7</version>
</dependency>
<!--了MT(]son web Token)登录支持-->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.o</version>
</dependency>

前台部分

公共配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 权限配置    白名单,jwt认证等等* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {//放行白名单ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();//循环白名单进行放行for (String url : ignoreUrlsConfig().getUrls()) {registry.antMatchers(url).permitAll();}//跨域请求//允许可以请求OPTIONS  CORSregistry.antMatchers(HttpMethod.OPTIONS).permitAll();//其他请求都需要身份认证registry.anyRequest().authenticated()// 关闭csrf跨站请求伪造 :因为现在使用jwt来实现认证.and().csrf().disable()// 禁止session   性能更好.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)// 自定义权限拒绝处理类.and().exceptionHandling()// 没有权限访问时的处理类.accessDeniedHandler(restfulAccessDeniedHandler())//没有登录时的处理类.authenticationEntryPoint(restfulAuthenticationEntryPoint()).and()//加入jwt认证过滤器.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}@Beanpublic JwtAuthenticationFilter jwtAuthenticationFilter(){return new JwtAuthenticationFilter();}@Beanpublic IgnoreUrlsConfig ignoreUrlsConfig(){return new IgnoreUrlsConfig();}@Beanpublic RestfulAccessDeniedHandler restfulAccessDeniedHandler(){return new RestfulAccessDeniedHandler();}@Beanpublic RestfulAuthenticationEntryPoint restfulAuthenticationEntryPoint(){return new RestfulAuthenticationEntryPoint();}@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
}

白名单绑定类

secure:ignored:urls: #安全路径白名单- /swagger-ui.html- /swagger-resources/**- /swagger/**- /**/v2/api-docs- /**/*.js- /**/*.css- /**/*.png- /**/*.ico- /webjars/springfox-swagger-ui/**- /actuator/**- /druid/**- /user/**- /home/**- /product/**- /order/paySuccess
@ConfigurationProperties(prefix = "secure.ignored")
public class IgnoreUrlsConfig {List<String> urls;public List<String> getUrls() {return urls;}public void setUrls(List<String> urls) {this.urls = urls;}
}

没有权限访问时的响应处理类

/*** @author* 没有权限访问时的响应处理类*/public class RestfulAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {response.setCharacterEncoding("UTF-8");response.setContentType("application/json");//响应403没有相关权限JSON json = JSONUtil.parse(CommonResult.failed(ResultCode.FORBIDDEN));//    FORBIDDEN(403, "没有相关权限"),response.getWriter().print(json);response.getWriter().flush();}
}

未登录处理类

/*** @author* 未登录时处理类*/
public class RestfulAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {response.setCharacterEncoding("UTF-8");response.setContentType("application/json");// 响应401 暂未登录或session已经过期JSON json = JSONUtil.parse(CommonResult.failed(ResultCode.UNAUTHORIZED));//UNAUTHORIZED(401, "暂未登录或session已经过期"),response.getWriter().print(json);}
}

JWT类

/*** @author* JWT 过滤器*/
public class JwtAuthenticationFilter extends OncePerRequestFilter {@AutowiredHttpServletRequest request;@Value("${jwt.tokenHeader}")private String tokenHeader;@Value("${jwt.tokenHead}")private String tokenHead;@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//jwt令牌   获取jwt令牌String jwt = request.getHeader(tokenHeader);if (!StrUtil.isBlank(jwt)&& jwt.startsWith(tokenHead)) {//字符串截取   截取Head 后面的字符串jwt =jwt.substring(tokenHead.length());//解密String userName = jwtTokenUtil.getUserNameFromToken(jwt);if (!StrUtil.isBlank(userName)) {//从服务器中查询用户  判断是否存在该用户UserDetails userDetails = userDetailsService.loadUserByUsername(userName);if (userDetails!=null) {//生成springsecurity的通过认证标识UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());SecurityContextHolder.getContext().setAuthentication(token);}}
//            filterChain.doFilter(request,response);//放行}filterChain.doFilter(request,response);//放行//        response.setCharacterEncoding("UTF-8");
//        response.setContentType("application/json");
//        //JWT为空
//        JSON json = JSONUtil.parse("用户名不存在");
//        response.getWriter().print(json);
//        response.getWriter().flush();}
}
jwt:secret: tuling-mall-portal   #可以用MD5加密  服务端私钥expiration: 86400  #24*60*60 一天tokenHead: Bearer  #JWT规范  #告诉客户端JWT令牌开头需要加的一个字符串tokenHeader: Authorization #告诉客户端在请求头里传什么参数名

配置UserDetailsSerrvice
在这里插入图片描述

在这里插入图片描述

启动注解(具体子类模块中 代码)
@EnableWebSecurity
在这里插入图片描述

登录方法

 @Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UmsMember login(String username, String password) {UmsMember umsMember = null;try {UserDetails userDetails = loadUserByUsername(username);umsMember= ((MemberDetails) userDetails).getUmsMember();if (!passwordEncoder.matches(password,umsMember.getPassword())) {Asserts.fail("密码不正确");}//生成springsecurity的通过认证标识UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);if (!userDetails.isEnabled()) {Asserts.fail("账号已被禁用");}insertLoginLog(username);//添加登录记录} catch (Exception e) {Asserts.fail("登录异常:" );e.printStackTrace();}return umsMember;}
/*** JwtToken生成的工具类* JWT token的格式:header.payload.signature* header的格式(算法、token的类型):* {"alg": "HS512","typ": "JWT"}* payload的格式(用户名、创建时间、生成时间):* {"sub":"wang","created":1489079981393,"exp":1489684781}* signature的生成算法:* HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)* Created on 2018/4/26.*/
public class JwtTokenUtil {public static ThreadLocal<String> currentUsername=new ThreadLocal<>();private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);private static final String CLAIM_KEY_USERNAME = "user_name";private static final String CLAIM_KEY_CREATED = "created";@Value("${jwt.secret}")private String secret;@Value("${jwt.expiration}")private Long expiration;@Value("${jwt.tokenHead}")private String tokenHead;/*** 根据负责生成JWT的token*/private String generateToken(Map<String, Object> claims) {return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.HS512, secret).compact();}/*** 从token中获取JWT中的负载*/private Claims getClaimsFromToken(String token) {Claims claims = null;try {claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();} catch (Exception e) {LOGGER.info("JWT格式验证失败:{}", token);}return claims;}/*** 生成token的过期时间*/private Date generateExpirationDate() {return new Date(System.currentTimeMillis() + expiration * 1000);}/*** 解密:从token中获取登录用户名(项目使用)*/public String getUserNameFromToken(String token) {String username;try {Claims claims = getClaimsFromToken(token);username = claims.get(CLAIM_KEY_USERNAME,String.class);} catch (Exception e) {username = null;}return username;}/*** 加密: 根据用户名生成token(项目使用)*/public String generateUserNameStr(String username) {Map<String, Object> claims = new HashMap<>();claims.put(CLAIM_KEY_USERNAME,username);claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}/*** 判断token是否已经失效*/private boolean isTokenExpired(String token) {Date expiredDate = getExpiredDateFromToken(token);return expiredDate.before(new Date());}/*** 从token中获取过期时间*/private Date getExpiredDateFromToken(String token) {Claims claims = getClaimsFromToken(token);return claims.getExpiration();}/*** 当原来的token没过期时是可以刷新的** @param oldToken 带tokenHead的token*/public String refreshHeadToken(String oldToken) {if(StrUtil.isEmpty(oldToken)){return null;}String token = oldToken.substring(tokenHead.length());if(StrUtil.isEmpty(token)){return null;}//token校验不通过Claims claims = getClaimsFromToken(token);if(claims==null){return null;}//如果token已经过期,不支持刷新if(isTokenExpired(token)){return null;}//如果token在30分钟之内刚刷新过,返回原tokenif(tokenRefreshJustBefore(token,30*60)){return token;}else{claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}}/*** 判断token在指定时间内是否刚刚刷新过* @param token 原token* @param time 指定时间(秒)*/private boolean tokenRefreshJustBefore(String token, int time) {Claims claims = getClaimsFromToken(token);Date created = claims.get(CLAIM_KEY_CREATED, Date.class);Date refreshDate = new Date();//刷新时间在创建时间的指定时间内if(refreshDate.after(created)&&refreshDate.before(DateUtil.offsetSecond(created,time))){return true;}return false;}
}

后台部分

核心处理role,user,resource之间的关系

配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 前台服务没有动态权限功能*/@Autowired(required = false)private SecuriResourceRoleSource securiResourceRoleSource;@Overrideprotected void configure(HttpSecurity http) throws Exception {//其他代码if (securiResourceRoleSource != null) {Map<String, List<String>> map = securiResourceRoleSource.getResourceRole();//循环注册if (!map.isEmpty()) {Set<Map.Entry<String, List<String>>> entries = map.entrySet();
//                for (Map.Entry<String, List<String>> entry : entries) {
//                    entry.getKey()
//                }Iterator<Map.Entry<String, List<String>>> iterator = entries.iterator();while (iterator.hasNext()) {Map.Entry<String, List<String>> next = iterator.next();//list转换数据,object[]转换为String[]List<String> list = next.getValue();String[] toArray = list.toArray(new String[list.size()]);registry.antMatchers(next.getKey()).hasAnyAuthority(toArray);}}}//其他代码}

SecuriResourceRoleSource 类

/*** @author* 核心是获取 用户user 角色role 资源resource*/
public interface SecuriResourceRoleSource {/*** 获取所有资源对应的角色* @return*///key 资源   /product/**// value  角色Map<String, List<String>> getResourceRole();
}
    @Autowiredprivate UmsResourceService resourceService;/*** 为Springsecurity配置的资源信息* @return*/@Beanpublic SecuriResourceRoleSource securiResourceRoleSource(){return new SecuriResourceRoleSource() {@Overridepublic Map<String, List<String>> getResourceRole() {//业务逻辑类 查询 对应的资源信息  用户  角色  资源三者关系List<ResourceRoleDto> list=resourceService.getResourceRole();Map<String, List<String>> map = new LinkedHashMap<>();for (ResourceRoleDto resourceRoleDto : list) {List<String> roleNameList = list.stream().map(r -> r.getName()).collect(Collectors.toList());map.put(resourceRoleDto.getUrl(),roleNameList);}return map;}};}

在这里插入图片描述
key为url
value为角色名
在这里插入图片描述
UserDetails中的getAuthorities()

   List<UmsRole> roleList;/*** 返回当前用户的角色信息* @return*/@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<GrantedAuthority> authorities = roleList.stream().map(role -> {return new SimpleGrantedAuthority(role.getName());}).collect(Collectors.toList());return authorities;}

User 类中

@Overridepublic UserDetails loadUserByUsername(String username) {UmsMember umsMember = getAdminByUsername(username);//根据用户id返回用户的角色List<UmsRole> roleList = roleMapper.getRoleList(umsMember.getId());if (umsMember!=null) {return new MemberDetails(umsMember,roleList);}throw  new ApiException("用户名或密码错误");}

在这里插入图片描述

动态发布

总的

在这里插入代码片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/90723.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3组件库

Vue组件库 ViteVue3TypescriptTSX 1、项目搭建 1.1、创建项目&#xff08;yarn&#xff09; D:\WebstromProject>yarn create vite yarn create v1.22.19 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh pa…

idea报错:java: 程序包org.springframework.web.bind.annotation不存在

这个错误通常都是maven仓库的问题&#xff0c;试了网上很多方法&#xff0c;都没有解决&#xff0c;如果大家有遇到这个问题&#xff0c;且试了很多方法之后都没有解决&#xff0c;不妨可以试试我这个方法 先编译一下已经写好的代码&#xff0c;这时候会出现以上报错&#xff…

文本分类实战-NLP

数据集及任务分析 项目主题&#xff1a;新闻的主题分类&#xff0c;10分类任务 一般对于NLP项目来说的话需要进行数据预处理的&#xff0c;但是由于本项目的数据是经过处理过的&#xff0c;所以就不需要进行数据预处理了&#xff0c;但是数据预处理对NLP项目是重中之重的。 TH…

Linux上安装温度监控软件

文章目录 Linux上安装温度监控软件IDRAC设置 Linux上安装温度监控软件 服务器的温度是影响服务器性能重要条件&#xff0c;怎么监控机器的温度呢&#xff0c;这里知道的有两种方式 通过管理界面&#xff0c;查看机器的温度通过机器上安装监监控软件来监控温度 在物理机上怎么…

微软电脑surface键盘无法使用问题解决

昨天下班后&#xff0c;正常关掉电脑&#xff0c;今天来上班发现键盘无法使用了 打人工找到了解决方法 开机->到锁屏页面->使用屏幕键盘输入密码进入电脑 然后右键左下角的win图标 找到设备管理器->键盘 全部右键卸载 再找到设备管理->系统设备 把这个DTX也卸…

腾讯云国际站代充-阿里云ECS怎么一键迁移到腾讯云cvm?

今天主要来介绍一下如何通过阿里云国际ECS控制台一键迁移至腾讯云国际CVM。腾讯云国际站云服务器CVM提供全面广泛的服务内容。无-需-绑-定PayPal&#xff0c;代-充-值腾讯云国际站、阿里云国际站、AWS亚马逊云、GCP谷歌云&#xff0c;官方授权经销商&#xff01;靠谱&#xff0…

【Microsoft 支持】【数据库-MySql】当您尝试从大于 5000 的 TCP 端口连接时收到错误 WSAENOBUFS (10055)

​ 一、转载原文 When you try to connect from TCP ports greater than 5000 you receive the error ‘WSAENOBUFS (10055)’ Symptoms If you try to set up TCP connections from ports that are greater than 5000, the local computer responds with the following WSAE…

大数据-玩转数据-Flink网页埋点PV统计

一、说明 衡量网站流量一个最简单的指标&#xff0c;就是网站的页面浏览量&#xff08;Page View&#xff0c;PV&#xff09;。用户每次打开一个页面便记录1次PV&#xff0c;多次打开同一页面则浏览量累计。 一般来说&#xff0c;PV与来访者的数量成正比&#xff0c;但是PV并不…

QT:自定义控件(Connect使用,子控件连接)

自定义控件封装&#xff1a; 1.添加新文件&#xff08;设计师界面类&#xff09;&#xff0c;创建子页面 &#xff0c;放自己想要的控件 2.在主页面中使用子控件 :新建一个widget-![在这里插入图片描述](https://img-blog.csdnimg.cn/95ed8015343e4c56a3914853950eff4c.png#pi…

【从零学习python 】27. Python 函数的使用及嵌套调用

文章目录 函数的文档说明1. 基本使用2. 高级使用 函数应用&#xff1a;打印图形和数学计算目标思考&实现1参考代码1 思考&实现2参考代码2 函数的嵌套调用进阶案例 函数的文档说明 1. 基本使用 def test(a, b):"用来完成对2个数求和" # 函数第一行写一个字…

从零开始 Spring Cloud 11:Elasticsearch II

从零开始 Spring Cloud 11&#xff1a;Elasticsearch II 图源&#xff1a;laiketui.com 在上篇文章中我们学习了 es 的基本功能&#xff0c;在本篇文章中会学习 es 的一些高级功能&#xff0c;比如&#xff1a; 聚合查询自动补全集群部署 数据聚合 类型 **聚合&#xff08…

【网络基础实战之路】基于BGP协议中的联邦号连接三个AS区域的实战详解

系列文章传送门&#xff1a; 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 【网络基础实战之路】基于…

超级品牌,都在打造数据飞轮

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 引入 「收钱吧到账15元。」 从北京大栅栏的糖葫芦铺子&#xff0c;到南京夫子庙的鸭血粉丝汤馆&#xff0c;再到广州珠江畔的早茶店&#xff0c;不知不觉间&#xf…

IntelliJ IDEA(简称Idea) 基本常用设置及Maven部署---详细介绍

一&#xff0c;Idea是什么&#xff1f; 前言&#xff1a; 众所周知&#xff0c;现在有许多编译工具&#xff0c;如eclipse&#xff0c;pathon, 今天所要学的Idea编译工具 Idea是JetBrains公司开发的一款强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要用于Java…

基于深度信念神经网络的矿石产量预测,基于DBN的矿石产量预测,DBN的详细原理

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) DBN的矿石产量预测 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类算法,本文将DBN算法进行矿石产量预测 DB…

Markdown编译器的使用

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

什么是BFC?它有什么作用?如何创建BFC?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是BFC⭐ BFC的作用⭐ 创建BFC的方法⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web…

如何在 3Ds Max 中准确地将参考图像调整为正确的尺寸?

您是否想知道如何在 3Ds Max 中轻松直观地调整参考图像的大小&#xff0c;而无需借助第三方解决方案、插件或脚本&#xff1f; 我问自己这个问题&#xff0c;并高兴地发现了FFD Box 2x2x2&#xff0c;我无法停止钦佩这个修改器的多功能性。 在本文中&#xff0c;我想与您分享一…

SQL server中substring 的用法

一&#xff1a;substring函数是SQL中截取字段数据中的其中一部分 --列&#xff1a;提取abdcsef中的abc数据&#xff0c;使用substring实现select substring(abdcsef,1,3) --‘1’表示截取的起始位置是从第一个字符开始,‘3’表示截取后得到的字符串长度为3个字符 二&#xff1…

item_get_sales-获取TB商品销量详情

一、接口参数说明&#xff1a; item_get_sales-获取商品销量详情&#xff0c;点击更多API调试&#xff0c;请移步注册API账号点击获取测试key和secret 公共参数 请求地址: https://api-gw.onebound.cn/taobao/item_get_sales 名称类型必须描述keyString是调用key&#xff08…