-
2021-05-11 14:19:19
Security+是针对信息安全基础级从业者的认证,偏重技术实操。无论是毕业生,还是没有经过正统安全教育的小白帽,甚至是信息安全管理岗位的资深人士和非安全岗位的运维及开发人员,Security+都不失为一门优秀的安全技术实操类培训。
Security+认证如此火爆的原因?
原因一:在所有信息安全认证当中,偏重信息安全技术的认证是空白的, Security+认证正好可以弥补信息安全技术领域的空白 。
目前行业内受认可的信息安全认证主要有CISP和CISSP,但是无论CISP还是CISSP都是偏重信息安全管理的,技术知识讲的宽泛且浅显,考试都是一带而过。而且CISSP要求持证人员的信息安全工作经验都要5年以上,CISP也要求大专学历4年以上工作经验,这些要求无疑把有能力且上进的年轻人的持证之路堵住。在现实社会中,无论是找工作还是升职加薪,或是投标时候报人员,认证都是必不可少的,这给年轻人带来了很多不公平。而Security+的出现可以扫清这些年轻人职业发展中的障碍,由于Security+偏重信息安全技术,所以对工作经验没有特别的要求。只要你有IT相关背景,追求进步就可以学习和考试。
原因二:IT运维人员工作与翻身的利器。
在银行、证券、保险、信息通讯等行业,IT运维人员非常多,IT运维涉及的工作面也非常广。是一个集网络、系统、安全、应用架构、存储为一体的综合性技术岗。虽然没有程序猿们“生当做光棍,死亦写代码”的悲壮,但也有着“锄禾日当午,不如运维苦“的感慨。天天对着电脑和机器,时间长了难免有对于职业发展的迷茫和困惑。Security+国际认证的出现可以让有追求的IT运维人员学习网络安全知识,掌握网络安全实践。职业发展朝着网络安全的方向发展,解决国内信息安全人才的匮乏问题。另外,即使不转型,要做好运维工作,学习安全知识取得安全认证也是必不可少的。
原因三:接地气、国际范儿、考试方便、费用适中!
CompTIA作为全球ICT领域最具影响力的全球领先机构,在信息安全人才认证方面是专业、公平、公正的。Security+认证偏重操作且和一线工程师的日常工作息息相关。适合银行、证券、保险、互联网公司等IT相关人员学习。作为国际认证在全球147个国家受到广泛的认可。
在目前的信息安全大潮之下,人才是信息安全发展的关键。而目前国内的信息安全人才是非常匮乏的,相信Security+认证一定会成为最火爆的信息安全认证。
报名Security+直播培训,您将获得:
1、赠送Security+录播视频、模拟题解析课程视频;
2、奖学金1000元京东卡:开班起3个月内,考试分数>800分,前10人获得奖学金;
3、赠送教材三本:官方图书、课程讲义、绝密题库(电子);
4、赠送ITIL V3、ITIL实务、ISO27001等在线视频课程;想要了解Security+认证更多情况及课程大纲,可以填写下方表单
https://www.jsform.com/web/formview/5f0673c975a03c5c8dd596d6
更多相关内容 -
SpringBoot2+MybatisPlus+SpringSecurity+jwt+redis+Vue人事管理系统源码.zip
2022-05-03 14:09:22SpringBoot2+MybatisPlus+SpringSecurity+jwt+redis+Vue人事管理系统源码,人事管理系统是基于当前流行技术组合的前后端分离:SpringBoot2+MybatisPlus+SpringSecurity+jwt+redis+Vue。 系统分为十一大模块:首页、... -
security+英文考试题库.pdf
2020-03-06 13:41:30Q1 :A security administrator wants to implement strong security on the company smart phones and terminal servers located in the data center. Drag and drop the applicable controls to each asset types? ... -
security+拖图题答案.pdf
2021-08-05 16:27:48security+拖图题答案.pdf -
SpringBoot+SpringSecurity+JWT+MybatisPlus实现基于注解的权限验证
2020-08-26 14:18:39SpringBoot+SpringSecurity+JWT+MybatisPlus实现基于注解的权限验证,可根据注解的格式不同,做到角色权限控制,角色加资源权限控制等,粒度比较细化。 @PreAuthorize("hasAnyRole('ADMIN','USER')"):具有admin或... -
CompTIA Security+ SY0-601 PDF V21.75
2021-08-29 15:41:23CompTIA Security+ SY0-601 PDF V21.75,考過PASS 應該與當時題目差不多,希望有幫到你們 -
CompTIA Security+ 学习指南
2020-01-24 14:20:11professor-messer-comptia-sy0-401-security-plus-study-guide-v5 -
SpringBoot2+Spring Security+Vue+ElementUI+蚂蚁金服AntV
2021-06-19 21:59:25课程概述该互联网实战项目是基于 Spring Boot 2+ SpringSecurity5+Element UI+Vue Admin Template+蚂蚁可视化AntV 等技术栈开发的项目,采用分布式,多模块,前后端分离开发。包括图形展示、权限管理、用户... -
Springboot整合Spring security+Oauth2+JWT搭建认证服务器,网关,微服务之间权限认证及授权
2021-04-22 11:15:37Springboot整合Spring security+Oauth2+JWT搭建认证服务器,网关,微服务之间权限认证及授权 -
SpringBoot+Security+Vue前后端分离开发权限管理系统
2021-06-19 22:06:26SpringSecurity5+Element?UI+Vue?Admin?Template+蚂蚁可视化AntV?等技术栈开发的项目,采用分布式,多模块,前后端分离开发。包括图形展示、权限管理、用户管理等功能。【后端技术】技术说明Spring?Boot2MVC框架?... -
Security+培训全套PPT汇总.zip
2021-08-19 16:22:03Security+培训全套PPT和知识点分享,供大家学习参考。 1、Security+培训-课程大纲(1) 2、Security+培训-安全基本概念(1.1) 3、Security+培训-网络安全(1.1) 4、Security+培训-合规与运维安全(1.1) 5、Security+培训... -
基于vue-cli脚手架以及基于SpringBoot+SpringSecurity+JWT+SpringDataJpa的权限管理系统.rar
2021-07-12 10:04:58基于vue-cli脚手架以及基于SpringBoot+SpringSecurity+JWT+SpringDataJpa的前后端java 项目 -
springboot+security+cas集成demo
2018-11-23 15:39:55springboot+security+cas集成demo。。 -
Spring security+jwt服务鉴权完整代码.zip
2019-09-09 11:17:56Spring security+jwt服务鉴权完整代码.实现服务鉴权访问, 携带token访问服务, 缺失或无效都提示401 -
springSecurity+springBoot+jwt架构
2018-04-03 16:10:18springSecurity+springBoot+jwt springSecurity+springBoot+jwt springSecurity+springBoot+jwt -
Security+认证学习/备考经验
2022-03-22 00:00:37Security+认证学习资料/备考经验一、Security+认证适合哪些人学习
”Security+ 认证是一种中立第三方认证,也是全球知名度最高的信息安全认证之一,其考试机构为美国计算机行业协会CompTIA 。Security+是和CISSP、CISA等共同包含在内的国际IT业10大热门认证之一,是美国国防部、美国国务院等10多个国家政府和权威组织指定的信息安全国际认证,并得到了Apple、Dell、HP、IBM、Intel 等众多企业的认可,作为国际认证在全球147个国家和地区受到广泛认可,被全球企业和安全专业人士所普遍采纳。“ 但是在中国区域,由于信息安全法律不同等原因,这个认证的知名度不高。
经过我一段时间的学习,认为Security+十分适合信息/网络安全领域的学生以及刚入行业的从业者学习,原因如下:
- 覆盖面广。Security+认证学习的内容几乎涉及到了cyber security中的所有领域,官网的介绍如图所示。学习该认证能够帮助入门者快速建立对整个安全领域的宏观认识。
- 学习内容难度不大。Security+作为一个入门认证,虽然覆盖了很多技术,但是很多的内容是点到为止,没有太过深入。当学习者完成了对于整个行业的初步学习后,可以进一步选择一个方向进行学习。
- 认证价格不贵。认证的费用大概是300多美元,换算后是2000多RMB。此外,不用报培训班,完全可以自己学习,节约培训成本。
- 提升英语水平。目前,对于Security+601的考试题目和学习课程(有字幕,语速适中清晰)都是全英文的,在学习过程中,能够帮助我们提升英语水平和熟悉更多的安全领域相关的名词。
- 没有工作年限要求。
二、学习资料
首先是学习视频。这里首推 Mike Chapple 在LinkedIn的学习资料(https://www.linkedin.com/learning/search?keywords=security%2B),课程大概20个小时左右,覆盖了所有的考试内容,有字幕,语速适中清晰。但是LinkedIn都课程中心已经不对中国大陆开放了,所以可以挂上VPN后注册一个海外账号, 然后免费领取1个月的学习会员进行学习(白嫖的好机会)。
第二,如果想要更加详细的学习知识点,并提升自己的英文材料阅读能力,可以去找一下security+ 601的学习指南的PDF(国内好像买不到纸质书)。该书的每一章节后面都有相关的测试题。
最后是我学习过程中翻译整理的 Mike Chapple 提供课程的学习笔记,链接如下:
https://blog.csdn.net/tushanpeipei/article/details/120356937三、备考过程
首先,Security+满分900分,750通过。考试的题目类型包括三种,由数目有多到少排序为:单选、多选和performance-based的题目(比如简单的配置防火墙,无线网络)。Performance-based大概会在整个考试中出现3道,然后总共的题目数量大约在80-90(MAX)道左右。
目前,Security+601的考试题库大概有600道左右,可以选择去买一个口碑较好的Dumps题库。一般里面包含了考试的百分之90以上的题库内容。但是需要注意的是,其中大概只有百分之80-90的题目是正确的,所以我们需要对于其中自己不确定的题目进行确认,确认的主要两个网站分别是:Chegg(https://www.chegg.com/)和Examtopics(https://www.examtopics.com/)。当然,对于很多不确定的概念,可以直接翻阅Security+学生指南或者google搜索wiki等网站进行确认。
其中Chegg主要是类似于百度知道的形式,如下所示:
当然这些”expert“回答的内容不一定是正确的,但是经过我的判断,大部分回答是没有问题的。对于Examtopics网站,里面目前有300道题左右,但是这个题库给出的很多答案也是错误的。好在它给了备考者一个交流讨论的平台,我们可以根据他们的讨论结果来最终判断自己该选择哪一个答案,具体页面如下所示:
当然,这两个网站如果都想查看完整的回答/题库,则需要付费,大概分别都是100RMB左右。最后就是买考卷然后进行考试了,考试提供了VUE的线上和线下两种形式,可以灵活选择,学习Mike Chapple课程或者买了学习指南,应该都可以拿到百分之10的折扣。
此外,想最后补充一句,该版本的考试不太适合死记硬背通过,因为考试的时候大概率会碰到几道没有见过的题目,此外,题库中也有不少的题目是错误的,需要自己学习后进行判断。祝想要通过该考试的同学都能如尝所愿。
- 覆盖面广。Security+认证学习的内容几乎涉及到了cyber security中的所有领域,官网的介绍如图所示。学习该认证能够帮助入门者快速建立对整个安全领域的宏观认识。
-
spring_security+OAuth2+JWT
2021-05-05 15:13:29spring_security+OAuth2+JWT -
任务1:Security+课程大纲.mp4
2021-07-03 10:17:38Security+课程大纲 -
SpringBoot+SpringSecurity+WebSocket
2017-04-11 18:16:23SpringBoot+SpringSecurity+WebSocket的整合Demo -
谷安天下Security+ ppt
2019-02-25 18:13:25谷安天下Security+ ppt。 Security+ 谷安天下内部培训ppt 谷安天下 security加培训资料 -
CompTIA Security+ Guide to Network Security Fundamentals(5th) 无水印pdf
2017-10-24 08:11:45CompTIA Security+ Guide to Network Security Fundamentals(5th) 英文无水印pdf 第5版 pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 ... -
security+学习资料.zip
2019-11-07 17:12:00Security+认证考试复习资料,主要内容包括:安全基础概念知识,网络安全知识,密码学知识,访问控制欲身份管理知识,安全威胁与漏洞介绍等等。 -
Security+ 认证
2017-10-16 12:15:22Security+ 认证是一种中立第三方认证,其发证机构为美国计算机行业协会CompTIA -
Springboot+Security+Jwt
2021-12-13 16:45:12随着业务的发展,传统的不分离前后端的Java项目逐渐减少,更多的时候是做到前后端分离,会话管理也就从传统的Session会话管理变为Jwt管理会话,本篇文章就是SpringBoot使用Jwt管理会话同时整合Security,完成权限...
工程目录文章目录
- 工程目录
- 前言
- 一、Security是什么?
- 二、使用步骤
- 总结:代码足够详细,有耐心的可以看,没耐心的浪费时间!
前言随着业务的发展,传统的不分离前后端的Java项目逐渐减少,更多的时候是做到前后端分离,会话管理也就从传统的Session会话管理变为Jwt管理会话,本篇文章就是SpringBoot使用Jwt管理会话同时整合Security,完成权限操作。
提示:以下是本篇文章正文内容,下面案例可供参考,可以按照工程目录进行拷贝搭建,希望对同行有所帮助!
一、Security是什么?它是一个管理权限的框架,它包含了认证【即验证用户名密码】和授权【即用户可执行的操作】
二、使用步骤
1.引入pom.xml文件代码如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent> <groupId>Security_Jwt</groupId> <artifactId>Security_Jwt</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>Security_Jwt Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.14.8</lombok.version> <druid.version>1.1.16</druid.version> <commonslang.version>2.6</commonslang.version> <redis.version>2.1.3.RELEASE</redis.version> <springfox.version>2.7.0</springfox.version> <mybatis.plus.boot.starter.version>3.0.1</mybatis.plus.boot.starter.version> <pagehelper.spring.boot.starter.version>1.2.10</pagehelper.spring.boot.starter.version> <mysql-connector.version>5.1.39</mysql-connector.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency> <!-- JWT依赖 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency> <!-- 引入 lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <!-- swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${springfox.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${springfox.version}</version> </dependency> <!-- pagehelper分页 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pagehelper.spring.boot.starter.version}</version> </dependency> <!-- mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis.plus.boot.starter.version}</version> </dependency> <!--mysql数据库依赖包--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>${redis.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> <scope>compile</scope> </dependency> <dependency> <groupId>apache-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.0</version> </dependency> </dependencies> <build> <finalName>Security_Jwt</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
2.application.yml文件代码如下:
server: port: 8080 #数据源 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/my_security_test?useUnicode=true&characterEncoding=UTF-8 username: root password: root #日期配置 yyyy-MM-dd HH:mm:ss jackson: date-format: yyyy-MM-dd HH:mm:ss #映射xml mybatis-plus: mapper-locations: classpath:mapping/*.xml type-aliases-package: com.dev.model configuration: #开启驼峰 map-underscore-to-camel-case: true #分页插件 pagehelper: auto-dialect: mysql reasonable: true support-methods-arguments: true # JWT配置 jwt: # 密匙Key secret: limoumou # HeaderKey tokenHeader: Authorization # Token前缀 tokenPrefix: Bearer # 过期时间,单位秒 expiration: 86400 # 配置白名单(不需要认证) antMatchers: /swagger-resources/**,/swagger-ui.html,/v2/api-docs,/webjars/**,/doc.html
3.启动类App8080.java
代码如下:
package com.dev; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @return {@link } * @throws * @author 李庆伟 * @date 2021/7/14 14:41 */ @SpringBootApplication public class App8080 { public static void main(String[] args) { SpringApplication.run(App8080.class,args); } }
4.Result.java
代码如下:
package com.dev.common; import com.alibaba.fastjson.JSON; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.servlet.ServletResponse; import java.io.PrintWriter; import java.util.List; /** * @author 李庆伟 * @date 2020/4/16 9:52 */ @Data public class Result { @ApiModelProperty(value = "返回码") private int code; @ApiModelProperty(value = "返回数据") private Object data; @ApiModelProperty(value = "返回描述") private String msg; @ApiModelProperty(value = "返回长度") private long count; /**返回成功 */ public static Result success(List<Object> data, long count){ Result result = new Result(); result.setCode(0);//成功 result.setMsg("成功");//提示语 result.setData(data); result.setCount(count); return result; } /**返回成功 */ public static Result success(List data){ Result result = new Result(); result.setCode(0);//成功 result.setMsg("成功");//提示语 result.setData(data); result.setCount(data == null || data.size() == 0 ? 0 : data.size()); return result; } /**返回成功 */ public static Result successForPage(List data,Integer count){ Result result = new Result(); result.setCode(0);//成功 result.setMsg("成功");//提示语 result.setData(data); result.setCount(count == null ? 0 : count); return result; } /**返回成功 */ public static Result success(){ Result result = new Result(); result.setCode(0);//成功 result.setMsg("成功");//提示语 return result; } /**返回成功 */ public static Result success(Object object){ Result result = new Result(); result.setCode(0);//成功 result.setMsg("成功");//提示语 result.setData(object);//返回内容 return result; } /**返回失败 */ public static Result error(){ Result result = new Result(); result.setCode(1);//失败 result.setMsg("失败");//提示语 return result; } /**返回失败 */ public static Result error(int code, String msg){ Result result = new Result(); result.setCode(code);//失败 result.setMsg(msg);//提示语 return result; } /**返回信息*/ public static Result response(int code, String msg, Object data) { Result result = new Result(); result.setCode(code); result.setMsg(msg); result.setData(data); return result; } /**Response输出Json格式 */ public static void responseJson(ServletResponse response, Object data) { PrintWriter out = null; try { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); out = response.getWriter(); out.println(JSON.toJSONString(data)); out.flush(); } catch (Exception e) { System.out.println("Response输出Json异常:" + e); } finally { if (out != null) { out.close(); } } } }
5.MyException.java
代码如下:
package com.dev.config.exception; /** * @author 李庆伟 * @date 2020/4/16 10:10 */ public class MyException extends RuntimeException{ private int code; private String msg; public MyException(int code, String msg){ super(msg); this.code = code; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } }
6.TopException
代码如下:
package com.dev.config.exception; import com.dev.common.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * @author 李庆伟 * @date 2020/4/16 10:11 */ @ControllerAdvice public class TopException { private Logger logger = LoggerFactory.getLogger(this.getClass()); @ExceptionHandler(value = Exception.class) @ResponseBody public Result handle(Exception e){ if(e instanceof MyException){ logger.error("业务日志",e); MyException myException = (MyException) e; return Result.error(myException.getCode(),myException.getMessage()); }else if(e instanceof AccessDeniedException){ return Result.error(403,"访问权限不足"); } logger.error("系统日志",e); return Result.error(1000,"业务繁忙"); } }
7.UserAccessDeniedHandler
代码如下:
package com.dev.config.security.handler; import com.dev.common.Result; 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; /** * 无权限处理类 * @author 李庆伟 * @date 2021/7/26 10:00 */ @Component public class UserAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { Result.responseJson(response, Result.response(403, "权限不足,拒绝访问", accessDeniedException.getMessage())); } }
8.UserAuthenticationProvider
代码如下:
package com.dev.config.security.handler; import com.dev.config.security.Md5Util; import com.dev.model.SysUserDetails; import com.dev.service.impl.SysUserDetailsService; import org.apache.commons.lang.StringUtils; 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.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; /** * @author 李庆伟 * @date 2021/7/26 10:49 */ @Component public class UserAuthenticationProvider implements AuthenticationProvider { @Autowired private SysUserDetailsService userDetailsService; /** * 身份验证 */ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = (String) authentication.getPrincipal(); // 获取用户名 String password = (String) authentication.getCredentials(); // 获取密码 if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { throw new UsernameNotFoundException("用户名或密码不能为空"); } if(username.equals("admin") && password.equals("123456")){ SysUserDetails sysUserDetails = (SysUserDetails) userDetailsService.loadUserByUsername(username); return new UsernamePasswordAuthenticationToken(sysUserDetails, password, sysUserDetails.getAuthorities()); } else if (username.equals("admin") && !password.equals("123456")){ throw new BadCredentialsException("用户名或密码错误"); } else { SysUserDetails sysUserDetails = (SysUserDetails) userDetailsService.loadUserByUsername(username); if (sysUserDetails == null) { throw new UsernameNotFoundException("用户名不存在"); } if(!sysUserDetails.getPassword().equals(Md5Util.MD5(password))){ throw new BadCredentialsException("用户名或密码错误"); } return new UsernamePasswordAuthenticationToken(sysUserDetails, password, sysUserDetails.getAuthorities()); } } /** * 支持指定的身份验证 */ @Override public boolean supports(Class<?> authentication) { return true; } }
9.UserLoginFailureHandler
代码如下:
package com.dev.config.security.handler; import com.dev.common.Result; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 登录失败处理类 * @author 李庆伟 * @date 2021/7/26 10:03 */ @Component public class UserLoginFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) { Result.responseJson(response, Result.response(500, "登录失败", exception.getMessage())); } }
10.UserLoginSuccessHandler
代码如下:
package com.dev.config.security.handler; import com.dev.common.Result; import com.dev.config.security.JWTTokenUtil; import com.dev.model.SysUserDetails; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; /** * 登录成功处理类 * @author 李庆伟 * @date 2021/7/26 10:02 */ @Component public class UserLoginSuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { SysUserDetails sysUserDetails = (SysUserDetails) authentication.getPrincipal(); String token = JWTTokenUtil.createAccessToken(sysUserDetails); Map<String, String> tokenMap = new HashMap<>(); tokenMap.put("token", token); Result.responseJson(response, Result.response(0, "登录成功", tokenMap)); } }
11.UserLogoutSuccessHandler
代码如下:
package com.dev.config.security.handler; import com.dev.common.Result; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 登出成功处理类 * @author 李庆伟 * @date 2021/7/26 10:04 */ @Component public class UserLogoutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { SecurityContextHolder.clearContext(); Result.responseJson(response, Result.response(200, "登出成功", null)); } }
12.UserNotLoginHandler
代码如下:
package com.dev.config.security.handler; import com.dev.common.Result; 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; /** * @author 李庆伟 * @date 2021/7/27 15:39 */ @Component public class UserNotLoginHandler implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { Result.responseJson(response, Result.response(401, "未登录", authException.getMessage())); } }
13.UserPermissionEvaluator
代码如下:
package com.dev.config.security.handler; import com.dev.config.exception.MyException; import com.dev.model.SysUserDetails; import com.dev.model.TSysRes; import com.dev.service.TSysResService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; import java.io.Serializable; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @author 李庆伟 * @date 2021/7/26 14:33 */ @Configuration @Component public class UserPermissionEvaluator implements PermissionEvaluator { @Autowired private TSysResService tSysResService; /** * 判断是否拥有权限 * [authentication, targetUrl, permission] * @return {@link boolean} * @throws * @author 李庆伟 * @date 2021/12/7 19:42 */ @Override public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) { SysUserDetails sysUserDetails = null; try { sysUserDetails = (SysUserDetails) authentication.getPrincipal(); } catch (Exception e){ throw new MyException(403,"权限不足"); } Set<String> permissions = new HashSet<String>(); // 用户权限 List<TSysRes> authList = tSysResService.findResByUserId(sysUserDetails.getId()); for (int i = 0; i < authList.size() ; i++) { permissions.add(authList.get(i).getPermission()); } // 判断是否拥有权限 if (permissions.contains(permission.toString())) { return true; } return false; } @Override public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { return false; } }
14.AutoSecurityConfig
代码如下:
package com.dev.config.security; import com.dev.config.security.handler.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; /** * @author 李庆伟 * @date 2021/7/26 14:36 */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法权限注解 public class AutoSecurityConfig extends WebSecurityConfigurerAdapter { /** * 无权限处理类 */ @Autowired private UserAccessDeniedHandler userAccessDeniedHandler; /** * 用户未登录处理类 */ @Autowired private UserNotLoginHandler userNotLoginHandler; /** * 用户登录成功处理类 */ @Autowired private UserLoginSuccessHandler userLoginSuccessHandler; /** * 用户登录失败处理类 */ @Autowired private UserLoginFailureHandler userLoginFailureHandler; /** * 用户登出成功处理类 */ @Autowired private UserLogoutSuccessHandler userLogoutSuccessHandler; /** * 用户登录验证 */ @Autowired private UserAuthenticationProvider userAuthenticationProvider; /** * 用户权限注解 */ @Autowired private UserPermissionEvaluator userPermissionEvaluator; /** * 加密方式,没使用这种加密方式 */ @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } /** * 注入自定义PermissionEvaluator * * @return */ @Bean public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() { DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler(); handler.setPermissionEvaluator(userPermissionEvaluator); return handler; } /** * 用户登录验证 */ @Override protected void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(userAuthenticationProvider); } @Value("${jwt.antMatchers}") private String antMatchers;//白名单,这里是不做验证的方法 /** * 安全权限配置 */ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 权限配置 .antMatchers(antMatchers.split(",")).permitAll()// 获取白名单(不进行权限验证) .anyRequest().authenticated() // 其他的需要登陆后才能访问 .and().httpBasic().authenticationEntryPoint(userNotLoginHandler) // 配置未登录处理类 .and().formLogin().loginProcessingUrl("/user/login")// 配置登录URL //.and().formLogin().loginPage("/user/login")// 配置登录URL .successHandler(userLoginSuccessHandler) // 配置登录成功处理类 .failureHandler(userLoginFailureHandler) // 配置登录失败处理类 .and().logout().logoutUrl("/logout/submit")// 配置登出地址 .logoutSuccessHandler(userLogoutSuccessHandler) // 配置用户登出处理类 .and().logout() //退出登录相关配置 .logoutSuccessUrl("/page/index") //退出成功后跳转的页面 .deleteCookies("JSESSIONID") //退出时要删除的Cookies的名字 .and().exceptionHandling().accessDeniedHandler(userAccessDeniedHandler)// 配置没有权限处理类 .and().cors()// 开启跨域 .and().csrf().disable(); // 禁用跨站请求伪造防护 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 禁用session(使用Token认证) http.headers().cacheControl(); // 禁用缓存 http.addFilter(new JWTAuthenticationFilter(authenticationManager())); 添加JWT过滤器 } }
15.JWTAuthenticationFilter
代码如下:
package com.dev.config.security; import com.dev.model.SysUserDetails; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author 李庆伟 * @date 2021/7/26 10:52 */ public class JWTAuthenticationFilter extends BasicAuthenticationFilter { public JWTAuthenticationFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { // 取出Token String token = request.getHeader(JWTConfig.tokenHeader); if (token != null && token.startsWith(JWTConfig.tokenPrefix)) { SysUserDetails sysUserDetails = JWTTokenUtil.parseAccessToken(token); if (sysUserDetails != null) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( sysUserDetails, sysUserDetails.getId(), sysUserDetails.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); } }
16.JWTConfig
代码如下:
package com.dev.config.security; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * @author 李庆伟 * @date 2021/7/26 9:54 */ @Component @ConfigurationProperties(prefix = "jwt") public class JWTConfig { /** * 密匙Key */ public static String secret; /** * HeaderKey */ public static String tokenHeader; /** * Token前缀 */ public static String tokenPrefix; /** * 过期时间 */ public static Integer expiration; /** * 配置白名单 */ public static String antMatchers; /** * 将过期时间单位换算成毫秒 * * @param expiration 过期时间,单位秒 */ public void setExpiration(Integer expiration) { this.expiration = expiration * 1000; } public void setSecret(String secret) { this.secret = secret; } public void setTokenHeader(String tokenHeader) { this.tokenHeader = tokenHeader; } public void setTokenPrefix(String tokenPrefix) { this.tokenPrefix = tokenPrefix + " "; } public void setAntMatchers(String antMatchers) { this.antMatchers = antMatchers; } }
17.JWTTokenUtil
代码如下:
package com.dev.config.security; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import com.dev.model.SysUserDetails; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import java.util.*; /** * @author 李庆伟 * @date 2021/7/26 9:57 */ @Slf4j public class JWTTokenUtil { /** * 创建Token * * @param sysUserDetails 用户信息 * @return */ public static String createAccessToken(SysUserDetails sysUserDetails) { String token = Jwts.builder().setId(// 设置JWT sysUserDetails.getId()) // 用户Id .setSubject(sysUserDetails.getUsername()) // 主题 .setIssuedAt(new Date()) // 签发时间 .setIssuer("limoumou") // 签发者 .setExpiration(new Date(System.currentTimeMillis() + JWTConfig.expiration)) // 过期时间 .signWith(SignatureAlgorithm.HS512, JWTConfig.secret) // 签名算法、密钥 .claim("authorities", JSON.toJSONString(sysUserDetails.getAuthorities())).compact(); // 自定义其他属性,如用户组织机构ID,用户所拥有的角色,用户权限信息等 return JWTConfig.tokenPrefix + token; } /** * 解析Token * * @param token Token信息 * @return */ public static SysUserDetails parseAccessToken(String token) { SysUserDetails sysUserDetails = null; if (StringUtils.isNotEmpty(token)) { try { // 去除JWT前缀 token = token.substring(JWTConfig.tokenPrefix.length()); // 解析Token Claims claims = Jwts.parser().setSigningKey(JWTConfig.secret).parseClaimsJws(token).getBody(); // 获取用户信息 sysUserDetails = new SysUserDetails(); sysUserDetails.setId(claims.getId()); sysUserDetails.setUsername(claims.getSubject()); // 获取角色 Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>(); String authority = claims.get("authorities").toString(); if (StringUtils.isNotEmpty(authority)) { List<Map<String, String>> authorityList = JSON.parseObject(authority, new TypeReference<List<Map<String, String>>>() { }); for (Map<String, String> role : authorityList) { if (!role.isEmpty()) { authorities.add(new SimpleGrantedAuthority(role.get("authority"))); } } } sysUserDetails.setAuthorities(authorities); } catch (Exception e) { log.error("解析Token异常:" + e); } } return sysUserDetails; } }
18.Md5Util
代码如下:
package com.dev.config.security; import java.security.MessageDigest; /** * @author 李庆伟 * @date 2021/7/28 15:54 */ public class Md5Util { public final static String MD5(String s) { char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; try { // 密码+盐组合 byte[] btInput = s.getBytes(); // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 mdInst.update(btInput); // 获得密文 byte[] md = mdInst.digest(); // 把密文转换成十六进制的字符串形式 int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 测试 * [args] * @throws * @author 李庆伟 * @date 2021/12/13 19:38 */ public static void main(String[] args) { String pwd = Md5Util.MD5("123456"); System.out.println(pwd ); } }
19.SwaggerConfig
代码如下:
package com.dev.config; import com.dev.App8080; import com.fasterxml.classmate.TypeResolver; import com.google.common.collect.Sets; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.OperationBuilder; import springfox.documentation.builders.ParameterBuilder; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.schema.ModelRef; import springfox.documentation.service.ApiDescription; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Parameter; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.ApiListingScannerPlugin; import springfox.documentation.spi.service.contexts.DocumentationContext; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 接口文档配置 * @return {@link } * @throws * @author 李庆伟 * @date 2021/7/19 17:15 */ @ConditionalOnWebApplication @Configuration @EnableSwagger2 public class SwaggerConfig implements ApiListingScannerPlugin { /** * Swagger2的配置文件,这里可以配置Swagger2的一些基本的内容,比如扫描的包等等 * [] * @return {@link Docket} * @throws * @author 李庆伟 * @date 2021/12/13 16:28 */ @Bean public Docket createRestApi() { List<Parameter> pars = new ArrayList<>(); ParameterBuilder token = new ParameterBuilder(); token.name("Authorization").description("Authorization") .modelRef(new ModelRef("string")) .parameterType("header") .required(false).build(); pars.add(token.build()); ParameterBuilder languageCode = new ParameterBuilder(); languageCode.name("languageCode").description("languageCode") .modelRef(new ModelRef("string")) .parameterType("header") .required(false).build(); pars.add(languageCode.build()); return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage(App8080.class.getPackage().getName())) .build() .globalOperationParameters(pars) .apiInfo(apiInfo()); } /** * 构建API文档的详细信息函数 * @return */ private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("项目接口 API") .version("1.0") .build(); } /** * Security指定的登录接口不会出现在swagger中,为了方便可以自定义登录接口在swagger中。 * [documentationContext] * @return {@link List<ApiDescription>} * @throws * @author 李庆伟 * @date 2021/12/13 16:20 */ @Override public List<ApiDescription> apply(DocumentationContext documentationContext) { return new ArrayList<ApiDescription>( Arrays.asList( new ApiDescription( "/user/login", //url "登录", //描述 Arrays.asList( new OperationBuilder( new CachingOperationNameGenerator()) .method(HttpMethod.POST)//http请求类型 .produces(Sets.newHashSet(MediaType.APPLICATION_JSON_VALUE)) .summary("登录") .notes("登录")//方法描述 .tags(Sets.newHashSet("登录"))//归类标签 .parameters( Arrays.asList( new ParameterBuilder() .description("用户名") .type(new TypeResolver().resolve(String.class)) .name("username") .parameterType("query") .parameterAccess("access") .required(true) .modelRef(new ModelRef("string")) //<5> .build(), new ParameterBuilder() .description("密码") .type(new TypeResolver().resolve(String.class)) .name("password") .parameterType("query") .parameterAccess("access") .required(true) .modelRef(new ModelRef("string")) //<5> .build() )) .build()), false))); } @Override public boolean supports(DocumentationType documentationType) { return DocumentationType.SWAGGER_2.equals(documentationType); } }
20.TSysUserController
代码如下:
package com.dev.controller; import com.dev.common.Result; import io.swagger.annotations.*; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; /** * 系统用户服务 * @author 李庆伟 * @date 2021/7/19 17:04 */ @Slf4j @RequestMapping("tSysUser") @RestController @Api(value = "系统用户服务", tags = "系统用户服务") public class TSysUserController { @PreAuthorize("hasRole('ROLE_/tSysUser/findByPage')") @PostMapping("findByPage") @ApiOperation(value = "添加系统用户", notes = "添加系统用户", produces = "application/json") public Result findByPage(){ log.info("测试用户分页查询权限"); return Result.success("测试用户分页查询权限"); } @PreAuthorize("hasRole('ROLE_/tSysUser/add')") @PostMapping("add") @ApiOperation(value = "添加系统用户", notes = "添加系统用户", produces = "application/json") public Result add(){ log.info("测试用户添加权限"); return Result.success("测试用户添加权限"); } @PreAuthorize("hasRole('ROLE_/tSysUser/edit')") @PostMapping("edit") @ApiOperation(value = "修改系统用户", notes = "修改系统用户", produces = "application/json") public Result edit(){ log.info("测试用户编辑权限"); return Result.success("测试用户编辑权限"); } @PreAuthorize("hasRole('ROLE_/tSysUser/delete')") @PostMapping("delete") @ApiOperation(value = "删除系统用户", notes = "删除系统用户", produces = "application/json") public Result delete(){ log.info("测试用户删除权限"); return Result.success("测试用户删除权限"); } }
21.TSysResMapper
代码如下:
package com.dev.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.dev.model.TSysRes; import org.apache.ibatis.annotations.Mapper; /** * @author 李庆伟 * @date 2021/7/19 17:06 */ @Mapper public interface TSysResMapper extends BaseMapper<TSysRes> { }
22.TSysRoleMapper
代码如下:
package com.dev.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.dev.model.TSysRole; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; /** * @author 李庆伟 * @date 2021/7/19 17:06 */ @Mapper public interface TSysRoleMapper extends BaseMapper<TSysRole> { /** * 根据用户名查询用户有的角色 * [userId] * @return {@link List<TSysRole>} * @throws * @author 李庆伟 * @date 2021/7/27 14:40 */ @Select("SELECT r.* FROM t_sys_role r " + "LEFT JOIN t_sys_user_role ur ON ur.role_id = r.id " + "WHERE " + "ur.user_id = #{userId} ") List<TSysRole> findRoleByUserId(String userId); }
23.TSysRoleResMapper
代码如下:
package com.dev.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.dev.model.TSysRoleRes; import org.apache.ibatis.annotations.Mapper; import java.util.List; import java.util.Map; /** * @author 李庆伟 * @date 2021/7/19 17:06 */ @Mapper public interface TSysRoleResMapper extends BaseMapper<TSysRoleRes> { List<String> selectRoleResByMap(Map<String, Object> map); }
24.TSysUserMapper
代码如下:
package com.dev.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.dev.model.TSysUser; import org.apache.ibatis.annotations.Mapper; /** * @author 李庆伟 * @date 2021/7/19 17:06 */ @Mapper public interface TSysUserMapper extends BaseMapper<TSysUser> { }
25.TSysUserRoleMapper
代码如下:
package com.dev.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.dev.model.TSysUserRole; import org.apache.ibatis.annotations.Mapper; /** * @author 李庆伟 * @date 2021/7/19 17:06 */ @Mapper public interface TSysUserRoleMapper extends BaseMapper<TSysUserRole> { }
26.SysUserDetails
代码如下:
package com.dev.model; import lombok.Data; import lombok.EqualsAndHashCode; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.io.Serializable; import java.util.Collection; /** * @author 李庆伟 * @date 2021/7/26 9:48 */ @Data @EqualsAndHashCode(callSuper = false) public class SysUserDetails extends TSysUser implements UserDetails, Serializable { private static final long serialVersionUID = 1L; /** * 用户角色 */ private Collection <GrantedAuthority> authorities; /** * 账号是否过期 */ private boolean isAccountNonExpired = false; /** * 账号是否锁定 */ private boolean isAccountNonLocked = false; /** * 证书是否过期 */ private boolean isCredentialsNonExpired = false; /** * 账号是否有效 */ private boolean isEnabled = true; /** * 获得用户权限 */ @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } /** * 判断账号是否过期 */ @Override public boolean isAccountNonExpired() { return isAccountNonExpired; } /** * 判断账号是否锁定 */ @Override public boolean isAccountNonLocked() { return isAccountNonLocked; } /** * 判断证书是否过期 */ @Override public boolean isCredentialsNonExpired() { return isCredentialsNonExpired; } /** * 判断账号是否有效 */ @Override public boolean isEnabled() { return isEnabled; } }
27.TSysRes
代码如下:
package com.dev.model; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.util.Date; /** * 系统资源实体 * @return {@link } * @throws * @author 李庆伟 * @date 2021/7/22 9:25 */ @Data @TableName("t_sys_res") public class TSysRes { @TableId private String id;//主键 private String name;//资源名称 private String resUrl;//资源路径 private String permission;//做拦截的code private String resType;//0菜单 1按钮 private String pid;//父级id private String icon;//菜单图标 private String createUser;//创建人 private Date createDate;//创建时间 }
28.TSysRole
代码如下:
package com.dev.model; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.util.Date; /** * 系统角色实体 * @author 李庆伟 * @date 2021/7/19 17:00 */ @Data @TableName("t_sys_role") public class TSysRole { @TableId private String id;//主键 private String roleName;//角色名称 private String roleExplain;//角色描述 private String createUser;//创建人 private Date createDate;//创建时间 }
29.TSysRoleRes
代码如下:
package com.dev.model; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; /** * 系统角色资源实体 * @author 李庆伟 * @date 2021/7/19 17:00 */ @Data @TableName("t_sys_role_res") public class TSysRoleRes { @TableId private String id;//主键 private String roleId;//角色id private String resId;//资源id }
30.TSysUser
代码如下:
package com.dev.model; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * 系统用户实体 * @author 李庆伟 * @date 2021/7/19 17:00 */ @Data @TableName("t_sys_user") public class TSysUser implements Serializable { private static final long serialVersionUID = 1L; @TableId private String id;//主键 private String username;//用户名 private String password;//密码 private String nickName;//昵称 private String cellPhone;//电话 private String mail;//邮件 private Date birthday;//生日 private String status;//状态(0-正常,1-禁用,2-删除) private String accountType;//1系统账号 2客户账号 private String inviteCode;//邀请码 private String sex;//性别:0男 1女 private String address;//地址 private Integer upNum;//获赞总量 private Integer readNum;//文章被阅读总量 private String sign;//签名 private String pictureId;//用户头像 private String createUser;//创建人 private Date createDate;//创建时间 }
31.TSysUserRole
代码如下:
package com.dev.model; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; /** * 系统用户角色实体 * @author 李庆伟 * @date 2021/7/19 17:00 */ @Data @TableName("t_sys_user_role") public class TSysUserRole { @TableId private String id;//主键 private String userId;//用户名id private String roleId;//角色id }
32.SysUserDetailsService
代码如下:
package com.dev.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.dev.model.SysUserDetails; import com.dev.model.TSysRes; import com.dev.model.TSysUser; import com.dev.dao.TSysResMapper; import com.dev.service.TSysResService; import com.dev.service.TSysUserService; import com.github.pagehelper.util.StringUtil; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; 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.stereotype.Service; import javax.annotation.Resource; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @author 李庆伟 * @date 2021/7/26 10:44 */ @Service public class SysUserDetailsService implements UserDetailsService { @Autowired private TSysUserService tSysUserService; @Resource private TSysResMapper tSysResMapper; @Autowired private TSysResService tSysResService; /** * 说明:重写UserDetailsService中的loadUserByUsername,就是查询用户详细信息封装到 UserDetails * 业务: * ①如果是admin会拥有全部权限 * ②如果不是admin就去查用户信息和用户拥有的权限 * [username] * @return {@link UserDetails} * @throws * @author 李庆伟 * @date 2021/12/7 19:49 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { List<TSysRes> resList = null; if(username.equals("admin")){ TSysUser tSysUser = new TSysUser(); tSysUser.setId("admin"); tSysUser.setUsername("admin"); tSysUser.setNickName("系统管理员"); SysUserDetails sysUserDetails = new SysUserDetails(); BeanUtils.copyProperties(tSysUser, sysUserDetails); Set<GrantedAuthority> authorities = new HashSet<>(); // 角色集合 //admin用户有的资源集合 resList = tSysResMapper.selectList(new QueryWrapper<>()); for (int i = 0; i < resList.size() ; i++) { if(StringUtil.isNotEmpty(resList.get(i).getPermission())){ authorities.add(new SimpleGrantedAuthority("ROLE_" + resList.get(i).getPermission())); } } sysUserDetails.setAuthorities(authorities); return sysUserDetails; } TSysUser tSysUser = tSysUserService.findByUsername(username); if (tSysUser != null) { SysUserDetails sysUserDetails = new SysUserDetails(); BeanUtils.copyProperties(tSysUser, sysUserDetails); Set<GrantedAuthority> authorities = new HashSet<>(); // 角色集合 resList = tSysResService.findResByUserId(sysUserDetails.getId());//当前用户有的资源集合 if(resList != null){ for (int i = 0; i < resList.size() ; i++) { if(StringUtil.isNotEmpty(resList.get(i).getPermission())){ authorities.add(new SimpleGrantedAuthority("ROLE_" + resList.get(i).getPermission())); } } } sysUserDetails.setAuthorities(authorities); return sysUserDetails; } return null; } }
33.TSysResServiceImpl
代码如下:
package com.dev.service.impl; import com.dev.model.TSysRes; import com.dev.model.TSysRole; import com.dev.dao.TSysResMapper; import com.dev.dao.TSysRoleMapper; import com.dev.dao.TSysRoleResMapper; import com.dev.service.TSysResService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 系统角色服务 * @author 李庆伟 * @date 2021/7/19 17:06 */ @Service public class TSysResServiceImpl implements TSysResService { @Resource private TSysResMapper tSysResMapper; @Resource private TSysRoleMapper tSysRoleMapper; @Resource private TSysRoleResMapper tSysRoleResMapper; /** * 根据用户id查询用户拥有的资源 * [userId] * @return {@link List< TSysRes>} * @throws * @author 李庆伟 * @date 2021/12/7 20:34 */ @Override public List<TSysRes> findResByUserId(String userId) { //获取用户有的角色 //根据当前登录用户获取角色 List<TSysRole> roleList = tSysRoleMapper.findRoleByUserId(userId); if(roleList == null || roleList.size() == 0){ //如果用户没有角色返回没有权限 return null; } //根据角色获取菜单资源id关系集合 Map<String,Object> map = new HashMap<>(); map.put("roleList",roleList); List<String> tSysRoleResList = tSysRoleResMapper.selectRoleResByMap(map); if(tSysRoleResList == null || tSysRoleResList.size() == 0){ //如果用户没有角色返回没有权限 return null; } //根据资源id获取菜单资源 return tSysResMapper.selectBatchIds(tSysRoleResList); } }
34.TSysRoleResServiceImpl
代码如下:
package com.dev.service.impl; import com.dev.service.TSysRoleResService; import org.springframework.stereotype.Service; /** * 系统角色资源服务 * @author 李庆伟 * @date 2021/7/19 17:06 */ @Service public class TSysRoleResServiceImpl implements TSysRoleResService { }
35.TSysRoleServiceImpl
代码如下:
package com.dev.service.impl; import com.dev.service.TSysRoleService; import org.springframework.stereotype.Service; /** * 系统角色服务 * @author 李庆伟 * @date 2021/7/19 17:06 */ @Service public class TSysRoleServiceImpl implements TSysRoleService { }
36.TSysUserRoleServiceImpl
代码如下:
package com.dev.service.impl; import com.dev.service.TSysUserRoleService; import org.springframework.stereotype.Service; /** * 系统用户角色服务 * @author 李庆伟 * @date 2021/7/19 17:06 */ @Service public class TSysUserRoleServiceImpl implements TSysUserRoleService { }
37.TSysUserServiceImpl
代码如下:
package com.dev.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.dev.model.TSysUser; import com.dev.dao.TSysUserMapper; import com.dev.service.TSysUserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * 系统用户服务 * @author 李庆伟 * @date 2021/7/19 17:06 */ @Service public class TSysUserServiceImpl implements TSysUserService { @Resource private TSysUserMapper tSysUserMapper; /** * 根据用户名查询用户 * [username] * @return {@link TSysUser} * @throws * @author 李庆伟 * @date 2021/7/27 11:11 */ public TSysUser findByUsername(String username) { QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq("username",username); return tSysUserMapper.selectOne(queryWrapper); } }
38.TSysResService
代码如下:
package com.dev.service; import com.dev.model.TSysRes; import java.util.List; /** * @author 李庆伟 * @date 2021/7/19 17:05 */ public interface TSysResService { List<TSysRes> findResByUserId(String userId); }
39.TSysRoleResService
代码如下:
package com.dev.service; /** * @author 李庆伟 * @date 2021/7/19 17:05 */ public interface TSysRoleResService { }
40.TSysRoleService
代码如下:
package com.dev.service; /** * @author 李庆伟 * @date 2021/7/19 17:05 */ public interface TSysRoleService { }
41.TSysUserRoleService
代码如下:
package com.dev.service; /** * @author 李庆伟 * @date 2021/7/19 17:05 */ public interface TSysUserRoleService { }
42.TSysUserServiceImpl
代码如下:
package com.dev.service; import com.dev.model.TSysUser; /** * @author 李庆伟 * @date 2021/7/19 17:05 */ public interface TSysUserService { TSysUser findByUsername(String username); }
库表【跟上篇文章的一样】:导入数据库sql
/* Navicat Premium Data Transfer Source Server : 本机数据库mysql Source Server Type : MySQL Source Server Version : 50143 Source Host : localhost:3306 Source Schema : my_security_test Target Server Type : MySQL Target Server Version : 50143 File Encoding : 65001 Date: 08/12/2021 21:17:27 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_sys_res -- ---------------------------- DROP TABLE IF EXISTS `t_sys_res`; CREATE TABLE `t_sys_res` ( `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源id', `name` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源名称', `res_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '资源路径', `permission` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '资源code', `res_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '0菜单 1按钮', `pid` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '父级id', `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, `create_date` datetime DEFAULT NULL, `icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '菜单图标' ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-资源表【菜单】' ROW_FORMAT = Compact; -- ---------------------------- -- Records of t_sys_res -- ---------------------------- INSERT INTO `t_sys_res` VALUES ('101', '用户添加', '/tSysUser/add', '/tSysUser/add', '1', '100', NULL, NULL, ''); INSERT INTO `t_sys_res` VALUES ('100', '用户管理', '/tSysUser/findByPage', '/tSysUser/findByPage', '0', '', NULL, NULL, 'fa fa-snowflake-o'); INSERT INTO `t_sys_res` VALUES ('102', '用户修改', '/tSysUser/edit', '/tSysUser/edit', '1', '100', NULL, NULL, 'fa fa-home'); INSERT INTO `t_sys_res` VALUES ('103', '用户删除', '/tSysUser/delete', '/tSysUser/delete', '1', '100', NULL, NULL, 'fa fa-home'); -- ---------------------------- -- Table structure for t_sys_role -- ---------------------------- DROP TABLE IF EXISTS `t_sys_role`; CREATE TABLE `t_sys_role` ( `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id', `role_name` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称', `role_explain` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述', `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人', `create_date` datetime DEFAULT NULL COMMENT '创建时间' ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-角色表' ROW_FORMAT = Compact; -- ---------------------------- -- Records of t_sys_role -- ---------------------------- INSERT INTO `t_sys_role` VALUES ('277144172094291968', '部门经理', '部门经理', NULL, '2021-08-27 10:22:51'); INSERT INTO `t_sys_role` VALUES ('277144675716956160', '普通员工', '普通员工', NULL, '2021-08-27 10:24:51'); INSERT INTO `t_sys_role` VALUES ('277646459757658112', '测试员工', '测试员工', '', '2021-08-28 19:38:46'); -- ---------------------------- -- Table structure for t_sys_role_res -- ---------------------------- DROP TABLE IF EXISTS `t_sys_role_res`; CREATE TABLE `t_sys_role_res` ( `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键', `role_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id', `res_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源id' ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-角色资源表中间表' ROW_FORMAT = Compact; -- ---------------------------- -- Records of t_sys_role_res -- ---------------------------- INSERT INTO `t_sys_role_res` VALUES ('1234', '277144675716956160', '101'); INSERT INTO `t_sys_role_res` VALUES ('12345', '277144675716956160', '100'); INSERT INTO `t_sys_role_res` VALUES ('123456', '277144172094291968', '100'); INSERT INTO `t_sys_role_res` VALUES ('123457', '277144172094291968', '101'); INSERT INTO `t_sys_role_res` VALUES ('123458', '277144172094291968', '102'); -- ---------------------------- -- Table structure for t_sys_user -- ---------------------------- DROP TABLE IF EXISTS `t_sys_user`; CREATE TABLE `t_sys_user` ( `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键', `username` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名', `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码', `nick_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '昵称', `cell_phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '手机号', `mail` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邮件', `birthday` datetime DEFAULT NULL COMMENT '生日', `status` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '状态(0-正常,1-删除,2-禁用)', `account_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '1系统账号 2客户账号', `invite_code` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邀请码', `sex` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '性别:0男 1女', `up_num` int(11) DEFAULT NULL COMMENT '所有获赞总量', `read_num` int(11) DEFAULT NULL COMMENT '所有文章阅读总量', `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '地址', `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人', `create_date` datetime DEFAULT NULL COMMENT '创建时间', `sign` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '用户签名', `picture_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '用户头像' ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-用户表' ROW_FORMAT = Compact; -- ---------------------------- -- Records of t_sys_user -- ---------------------------- INSERT INTO `t_sys_user` VALUES ('276866508766838784', 'liqingwei', 'E10ADC3949BA59ABBE56E057F20F883E', '李庆伟', '15801174628', 'liqingwei01@cnpc.cn', NULL, '0', '1', '3781941dd39446b89e98cb661766aade', NULL, 0, 0, NULL, NULL, '2021-08-26 15:59:31', NULL, NULL); INSERT INTO `t_sys_user` VALUES ('277657251341139964', 'zhangsan', 'E10ADC3949BA59ABBE56E057F20F883E', '张三', '15801174626', 'zhangsan@qq.com', '2021-08-04 00:00:00', '0', '1', 'ea819ca462914e938943752d48ae8bcc', '0', 0, 0, '河南北京北', 'admin', '2021-08-28 20:21:38', '啥也不是。。。', '287348042074423296'); -- ---------------------------- -- Table structure for t_sys_user_role -- ---------------------------- DROP TABLE IF EXISTS `t_sys_user_role`; CREATE TABLE `t_sys_user_role` ( `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键', `user_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户id', `role_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-用户角色中间表' ROW_FORMAT = Compact; -- ---------------------------- -- Records of t_sys_user_role -- ---------------------------- INSERT INTO `t_sys_user_role` VALUES ('111', '276866508766838784', '277144675716956160'); INSERT INTO `t_sys_user_role` VALUES ('222', '277657251341139964', '277144172094291968'); SET FOREIGN_KEY_CHECKS = 1;
测试【把登录接口加到swagger中了】:
访问地址:http://localhost:8080/swagger-ui.html
总结
一点点。。。。。。。。。。。
-
Spring Security + Oauth2 认证授权
2022-05-02 18:45:42文章目录前言一、Spring Security + Oauth2 认证的4种模式1.1 授权码模式1.2 简化模式1.3 密码模式1.4 客户端模式二、使用步骤1.引入库2.读入数据总结 前言 微服务开发这么流行,安全认证非常重要,Spring Security...相对较全面的 Spring Security Oauth2 认证授权框架
前言
微服务开发这么流行,安全认证非常重要,Spring Security + Oauth2 作为一个 认证授权的框架,不可缺。
在此简单说明并且做学习笔记。
开发工具:IDEA
一、Spring Security + Oauth2 认证的4种模式
1.1 授权码模式(authorization_code)
授权码是相对比较安全的模式,需要用户首先通过接口获取一个 授权码,然后再用 client_id 和 client_secret 加上 获取到的授权码进行认证。
1.2 简化模式(implicit)
简化模式多用于单一应用,没有服务端的第三方单页面应用,因为没有服务器端就无法接受授权码。
1.3 密码模式 (password)
密码模式一般用于我们自己开发的,第一方原生APP或者是第一方面页面应用;因为会暴露密码出来,所以最好client端是自己开发的或者我们比较信任的
1.4 客户端模式(client_credentials)
我们对client足够信任的情况下使用客户端模式,客户端本身提供的 client_id 和 client_secret 进行认证
二、项目搭建
2.1 添加依赖 pom.xml
因为使用的是 Spring security + Oauth2 进行认证与授权的,所以要添加 Spring security 和 Oauth2 的依赖包;
也是一个web项目,所以需要添加 boot 的 web 包。
版本:版本是 2.x<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> </dependencies>
2.2 配置安全规则
2.2.1 web安全规则配置
2.2.2.1 规则配置类
@Configuration @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Resource ClientAccessDeniedHandler clientAccessDeniedHandler; @Autowired UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider; /** * 配置 Http 请求 安全策略 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() //关闭 csrf 保护 .authorizeRequests().antMatchers(HttpMethod.OPTIONS,"/login","/oauth/**").permitAll() //配置哪些路径可以访问 .anyRequest().authenticated() //配置所有的请求都要权限验证 .and() .formLogin().loginPage("/login.html") //自定义登录页面 .and() .exceptionHandling().accessDeniedHandler(clientAccessDeniedHandler); //配置访问受限时的情况 //super.configure(http); } /** * 配置一个 provider 进行用户信息的获取和验证操作 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(usernamePasswordAuthenticationProvider); } /** * 初始化一个 provider 提供校验操作 * @return * @throws Exception */ @Bean public AuthenticationManager authenticationManager() throws Exception { return new ProviderManager(usernamePasswordAuthenticationProvider); } /** * 设置密码加密方式 * @return */ @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
2.2.2.2 依赖的认证操作 provider
@Component public class UsernamePasswordAuthenticationProvider implements AuthenticationProvider { /** * 这里使用 UserDetailService 进行加载用户信息 */ @Autowired WeshUserDetailService userDetailService; /** * 认证方法 * @param authentication * @return * @throws AuthenticationException */ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String principle = authentication.getPrincipal().toString(); //username String credential = authentication.getCredentials().toString(); //password UserDetails userDetails = userDetailService.loadUserByUsername(principle); return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(),userDetails.getAuthorities()); } /** * 判断是不是使用此 provider 进行认证操作,返回true 则在认证的时候执行上面的 authenticate() 方法 * @param aClass * @return */ @Override public boolean supports(Class<?> aClass) { return aClass.equals(UsernamePasswordAuthenticationToken.class); } }
2.2.2.3 加载用户信息的 UserDetailsService
@Component public class WeshUserDetailService implements UserDetailsService { /** * 框架会掉此方法加载用户信息 * @param username * @return * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { if("100001".equals(username)){ User user = new User("100001","admin001", Collections.emptyList()); return user; } return null; } }
2.2.2 认证规则配置
2.2.2.1 规则配置
@Configuration @EnableAuthorizationServer public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter{ @Autowired private AuthenticationManager authenticationManager; @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Autowired private WeshClientDetailsService clientDetailsService; @Autowired private TokenStore tokenStore; /** * 配置登录用户信息服务 * @param configurer * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer configurer) throws Exception { //配置数据库获取客户信息 configurer.withClientDetails(clientDetailsService); //super.configure(clients); } /** * 配置令牌 * @param endpoints * @throws Exception */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) //需要提供一个认证管理器 .accessTokenConverter(jwtAccessTokenConverter) //jwt 进行密码转换加密 .tokenServices(tokenServices()) //token 管理服务 .allowedTokenEndpointRequestMethods(HttpMethod.POST); //super.configure(endpoints); } /** * 配置终端(api) * @param security * @throws Exception */ @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.tokenKeyAccess("permitAll()") //token/token_key .checkTokenAccess("permitAll()") //check_token .allowFormAuthenticationForClients(); //允许表单认证提交,不放开,登录页面表单提交不了 //super.configure(security); } @Bean public AuthorizationServerTokenServices tokenServices(){ DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setClientDetailsService(clientDetailsService); //配置生成token获取用户信息服务 tokenServices.setTokenStore(tokenStore); //token 存储服务 tokenServices.setReuseRefreshToken(true); tokenServices.setAccessTokenValiditySeconds(7200); tokenServices.setReuseRefreshToken(false); // 设置为 true, 则没有 refresh_token 在返回体中 tokenServices.setSupportRefreshToken(true); //支持 refresh token tokenServices.setRefreshTokenValiditySeconds(259200); //刷新令牌3天有效期 //设置token的加密方式为 JWT TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter)); tokenServices.setTokenEnhancer(tokenEnhancerChain); return tokenServices; } }
2.2.2.2 客户端信息查询服务
@Service public class WeshClientDetailsService implements ClientDetailsService { /** * 实现具体如何读取用户信息 * 项目中可以用从数据库中查询 * @param s * @return * @throws ClientRegistrationException */ @Override public ClientDetails loadClientByClientId(String s) throws ClientRegistrationException { Client client = new Client(); if("100001".equals(clientId)){ //授权码模式需要提供跳转地址 100001 作为授权码账号 client.setClientId("100001"); client.setClientSecret(new BCryptPasswordEncoder().encode("admin001")); client.getScope().add("all"); //权限范围是all,所有 client.getAuthorizedGrantTypes().add("authorization_code"); client.getRegisteredRedirectUri().add("http://www.baidu.com"); } if("100002".equals(clientId)){ // 100002 作为 password 模式跳转 client.setClientId("100002"); client.setClientSecret(new BCryptPasswordEncoder().encode("admin001")); client.getScope().add("all"); //权限范围是all,所有 } return client; } }
2. Token 配置
/** * Token 配置 jwt 加密 */ @Configuration public class TokenConfig { /** * jwt 配置的一个 签名 */ private final String SIGNING_KEY = "*****"; /** * 初始化 token store 来存储token * @return */ @Bean public TokenStore tokenStore(){ return new JwtTokenStore(jwtAccessTokenConverter()); } /** * jwt 加密token配置 * @return */ @Bean public JwtAccessTokenConverter jwtAccessTokenConverter(){ JwtAccessTokenConverter tokenConverter = new JwtAccessTokenConverter(); tokenConverter.setSigningKey(SIGNING_KEY); return tokenConverter; } }
2.3 启动测试
2.3.1 授权码测试
2.3.1.1 请求获取授权码
http://localhost:9999/uaa/oauth/authorize?client_id=client01&response_type=code&scope=all&redirect_uri=http://www.baidu.com (GET)
参数说明:
client_id: 用户id
client_secret: 用户密码
response_type: 请求认证方式,值为 ‘code’
点击Authorize之后,会跳转到 redirect url,并传参授权码
2.3.1.2 请求认证接口
按照授权码获取token
2.3.2 简化模式测试
2.3.2.1 请求
http://localhost:9999/uaa/oauth/authorize?client_id=client01&response_type=token&scope=all&redirect_uri=http://www.baidu.com (GET)
注意:response_type是 token
调用授权接口,和 授权码模式同一个接口,不过 response_type 是 token
2.3.2.2 响应跳转
返回结果:
注意:链接中的 ‘#’ , URI 中的 fragment 用来标识初级资源
2.3.3 密码模式测试
http://localhost:9999/uaa/oauth/token(POST)
参数:
client_id=client01,
client_secret=client01,
grant_type=password,
username=zhangsan,
password=123
2.3.4 客户端模式测试
http://localhost:9999/uaa/oauth/token
参数
client_id=client01
client_secret=client01
grant_type=client_credentials
总结
spring security + oauth2进行了简单的搭建和记录,大致理解了 spring security oauth2 框架,项目初始搭建完成,不过此框架还有很多细节部分需要再深究。
自己总结的往往影响比较深刻,哪怕忘记了,看自己的文章也更熟悉。
而且我的文章目录清晰,可以迅速定位到需要看的那部分。
项目源码
有详细注释。
如果令尊看到这里了,希望不要浪费您的宝贵的实际,这篇简短的文章能帮助到令尊!!! -
security+ 备考专用笔记
2019-04-22 09:13:58security+ 备考专用笔记 知识点概念等备考总结,security+ 备考专用笔记 知识点概念等备考总结。 -
SpringBoot+SpringSecurity+JWT实现认证和授权
2021-01-17 23:40:52dbcp,c3p0) SpringBoot+SpringSecurity+mysql实现认证与授 SpringBoot+Spring Security基于内存用户认证 SpringBoot+WebSocket在线聊天室、消息推送 SpringBoot+SpringData JPA操作Mysql数据库 SpringBoot热部署... -
Spring Security + OAuth2.0
2021-02-17 16:26:45授权服务器 授权服务器中有4个端点。说明如下: Authorize Endpoint :授权端点,进行...Spring Security Oauth2架构 说明如下: 用户访问,此时没有Token。Oauth2RestTemplate会报错,这个报错信息会被Oauth2Cli -
前后端分离 -- Spring Boot + Spring Security + Vue + ElementUI 实现用户认证
2022-01-24 08:46:41前后端分离 -- Spring Boot + Spring Security + Vue + ElementUI 实现用户认证