关于springsecurity:Spring-Security6-全新写法大变样

@[toc]Spring Security 在最近几个版本中配置的写法都有一些变动,很多常见的办法都废除了,并且将在将来的 Spring Security7 中移除,因而松哥在去年旧文的根底之上,又补充了一些新的内容,从新发一下,供各位应用 Spring Security 的小伙伴们参考。 接下来,我把从 Spring Security5.7 开始(对应 Spring Boot2.7 开始),各种已知的变动都来和小伙伴们梳理一下。 1. WebSecurityConfigurerAdapter 首先第一点,就是各位小伙伴最容易发现的 WebSecurityConfigurerAdapter 过期了,在目前最新的 Spring Security6.1 中,这个类曾经齐全被移除了,想凑合着用都不行了。 精确来说,Spring Security 是在 5.7.0-M2 这个版本中将 WebSecurityConfigurerAdapter 过期的,过期的起因是因为官网想要激励各位开发者应用基于组件的平安配置。 那么什么是基于组件的平安配置呢?咱们来举几个例子: 以前咱们配置 SecurityFilterChain 的形式是上面这样: @Configurationpublic class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authz) -> authz .anyRequest().authenticated() ) .httpBasic(withDefaults()); }}那么当前就要改为上面这样了: @Configurationpublic class SecurityConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authz) -> authz .anyRequest().authenticated() ) .httpBasic(withDefaults()); return http.build(); }}如果懂之前的写法的话,上面这个代码其实是很好了解的,我就不做过多解释了,不过还不懂 Spring Security 根本用法的小伙伴,能够在公众号后盾回复 ss,有松哥写的教程。 ...

June 14, 2023 · 7 min · jiezi

关于springsecurity:创建SpringSecurity项目

前言 在上一章节中,曾经带大家意识了Spring Security,对其基本概念已有所理解,然而作为一个合格的程序员,最要害的必定还是得动起手来,所以从本篇文章开始,我就带大家搭建第一个Spring Security我的项目,看看如何利用Spring Security来爱护咱们的Java Web我的项目。 一. 搭建SpringBoot开发环境 咱们的Spring Security系列教程会基于SpringBoot环境,并且以案例迭代的形式进行开发,所以为了不便后续案例的编写,咱们先提前搭建一个SpringBoot环境的Web我的项目。 1.创立SpringBoot我的项目如各位对SpringBoot根底不相熟,请参考自己的SpringBoot系列教程:blog.csdn.net/syc000666/a…SpringBoot我的项目的具体创立过程如下图所示。 1.1 创立一个基于Maven的Project我的项目。 1.2 设置项目名称和存储地位 2.增加我的项目依赖在pom.xml文件中,增加配置SpringBoot开发环境的依赖包。 <properties> <java.version>1.8</java.version><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.2.5.RELEASE</spring-boot.version><spring-platform.version>Cairo-SR3</spring-platform.version></properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency><!--BOM(bill of materials):资料清单,用于解决jar包依赖的好办法--> <!--缘起:Spring当初已倒退成一个宏大体系。比方security、mvc等。如此一来,不同模块或者与内部进行集成时, 依赖解决就须要各自对应版本号。比方,较新spring与较老的quartz,它们集成就会遇到问题,给搭建和降级带来不便。 因而Spring IO Platform应运而生,只有我的项目中引入了它,内部集成时依赖关系无需版本号。--> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>${spring-platform.version}</version> <type>pom</type> <scope>import</scope> </dependency></dependencies></dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies><build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins></build><!--配置地方仓库--><repositories> <repository> <id>aliyun-repos</id> <url>https://maven.aliyun.com/repository/public</url> <snapshots> <enabled>false</enabled> </snapshots> </repository></repositories> 复制代码增加完SpringBoot中次要的依赖包之后,咱们就能够在这个环境中进行Web我的项目开发了。 二. 创立第一个SpringSecurity我的项目咱们在下面的SpringBoot开发环境中,创立出第一个SpringSecurity模块,具体创立过程略(嘿嘿)。 1.增加模块中的pom依赖咱们在该module中,增加我的项目开发时必要的依赖包,次要是增加SpringSecurity的依赖包,在这里会完满体现SpringBoot中”约定大于配置“的思维哦。 <dependencies> <dependency> ...

April 12, 2023 · 1 min · jiezi

关于springsecurity:Spring-Security-中的核心对象

Spring Security 的外围对象实用于 Spring Security 5.4.x 以上版本.SecurityFilterChain依据匹配规定Spring Security 中的过滤器链对象, 在没有自定义 SecurityFilterChain 注入Ioc 容器时,在Spring Boot 主动配置类中,默认向 Ioc 容器中注入一个 defaultSecurityFilterchain 对象. 通过@ConditionalOnDefaultWebSecurity 注解实现该成果. 默认 SecurityFilterChain 按程序执行上面的过滤器: FilterChainProxySecurity 的所有过滤器的 代理类, 实现Filter 接口.HttpSecurity用于构建过滤器链的对象HttpSecurity 被 @Scope("protopye") 润饰,因而在其余 Bean 中注入 HttpSecurity Bean 时,会以该办法创立的对象作为原型,创立一个新的 HttpSecurity. 也称为多例Bean. 在构建每个过滤器链 SecurityFilterChain 时,都会创立一个新的 HttpSecurity. WebSecurity用于构建 FilterChainProxy Bean. Spring Boot 对 Security 的自动化配置UserDetailsServiceAutoConfiguration配置默认的用户管理器: InMemoryUserDetailsManager 详情参考:[源码分析用户信息的管理者 --userdetailsmanager

March 2, 2023 · 1 min · jiezi

关于springsecurity:源码剖析用户信息的管理者UserDetailsManager

Spring Security 的作为守门员,其两大性能:认证(Authentication) 和 受权(authorization)学而思: Spring Security 是如何对用户进行治理的?初始化我的项目并启动初始化一个 Spring Boot 我的项目并编写一个接口,在没有引入 Spring Security 依赖时,接口是可能能失常拜访的。 @RestController@RequestMapping("/user")public class UmsAdminController { @GetMapping("/details") public Object userInfos() { return "用户详情"; }}<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency><dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope></dependency>在引入依赖后,再次申请接口 http://localhost:8080/user/details ,页面跳转至了登录页面。 用户默认名为 user , 默认明码是每次启动利用时随机生成的,启动利用时,显示在了控制台中。 UserDetailsManager明明什么都没干,只是引入平安的框架,为什么申请接口就被拦挡?这就与 Spring Security 的机制无关,Spring Security 采纳了”默认回绝“ 的安全策略。意思是资源默认对未认证受权用户禁止拜访。为须要凋谢的资源进行属性配置,而不是默认对资源进行凋谢,这被认为是一种良好的平安做法。 在申请接口前,Spring Security 采纳了过滤器对接口进行拦挡认证(过滤器是Security 的外围局部,这个之后再详述)。认证过程中用到 UserDetailsManager ,也就是本章的配角。 UserDetailsManager 是治理用户的接口,继承了 UserDetailsService 接口,UserDetailsService 提供了加载用户详细信息(UserDetails)的办法(loadUserByUsername) 。 UserDetails: 用户详细信息的接口,对用户的形象,提供了获取用户名和明码等办法UserDetailsService:提供了一个加载用户的办法,该办法依据用户名从存储(内存、数据库等)中查问出用户对象(UserDetails),认证过程最终就是通过调用该办法,来认证用户。UserDetailsManager:在 UserDetailsService 根底上减少了 增删改等性能,实现了对用户的治理。 两个实现类在Spring Security 中 ,UserDetailsManager 有两个实现类,如下图: InMemoryUserDetailsManager:基于内存的用户管理器,我的项目初始化时默认应用,不能满足业务需要JdbcUserDetailsManager:基于数据库的用户管理器,更合乎实在业务的需要 InMemoryUserDetailsManager先来摸索 InMemoryUserDetailsManager 在Security 中是如何构建的。 ...

March 2, 2023 · 1 min · jiezi

关于springsecurity:Spring-Security实现多种认证方式

一、引言理论零碎通常须要实现多种认证形式,比方用户名明码、手机验证码、邮箱等等。Spring Security能够通过自定义认证器AuthenticationProvider 来实现不同的认证形式。接下来介绍一下SpringSecurity具体如何来实现多种认证形式。 二、具体步骤这里咱们以用户名明码、手机验证码两种形式来进行演示,其余一些登录形式相似。 2.1 自定义认证器AuthenticationProvider首先针对每一种登录形式,咱们能够定义其对应的认证器AuthenticationProvider,以及对应的认证信息Authentication,理论场景中这两个个别是配套应用。认证器AuthenticationProvider有一个认证办法authenticate(),咱们须要实现该认证办法,认证胜利之后返回认证信息Authentication。 2.1.1 手机验证码针对手机验证码形式,咱们能够定义以下两个类MobilecodeAuthenticationProvider.class import com.kamier.security.web.service.MyUser;import org.springframework.security.authentication.AuthenticationProvider;import org.springframework.security.authentication.BadCredentialsException;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import java.util.HashMap;import java.util.Map;public class MobilecodeAuthenticationProvider implements AuthenticationProvider { private UserDetailsService userDetailsService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { MobilecodeAuthenticationToken mobilecodeAuthenticationToken = (MobilecodeAuthenticationToken) authentication; String phone = mobilecodeAuthenticationToken.getPhone(); String mobileCode = mobilecodeAuthenticationToken.getMobileCode(); System.out.println("登陆手机号:" + phone); System.out.println("手机验证码:" + mobileCode); // 模仿从redis中读取手机号对应的验证码及其用户名 Map<String, String> dataFromRedis = new HashMap<>(); dataFromRedis.put("code", "6789"); dataFromRedis.put("username", "admin"); // 判断验证码是否统一 if (!mobileCode.equals(dataFromRedis.get("code"))) { throw new BadCredentialsException("验证码谬误"); } // 如果验证码统一,从数据库中读取该手机号对应的用户信息 MyUser loadedUser = (MyUser) userDetailsService.loadUserByUsername(dataFromRedis.get("username")); if (loadedUser == null) { throw new UsernameNotFoundException("用户不存在"); } else { MobilecodeAuthenticationToken result = new MobilecodeAuthenticationToken(loadedUser, null, loadedUser.getAuthorities()); return result; } } @Override public boolean supports(Class<?> aClass) { return MobilecodeAuthenticationToken.class.isAssignableFrom(aClass); } public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; }}留神这里的supports办法,是实现多种认证形式的要害,认证管理器AuthenticationManager会通过这个supports办法来断定以后须要应用哪一种认证形式。 ...

February 24, 2023 · 4 min · jiezi

关于spring-security:Spring-Security-–-RequestRejectedException

概述Spring Security 提供了 RequestRejectedHandler 来解决当申请被回绝时候如何解决,在没有进行配置的状况下,默认是应用 DefaultRequestRejectedHandler 间接将异样进行抛出: throw requestRejectedException;同时也提供了 HttpStatusRequestRejectedHandler 来返回对应的状态码。 定制 RequestRejectedHandlerRequestRejectedHandler 的注入是在 WebSecurity 的 setApplicationContext 当中: try { this.requestRejectedHandler = applicationContext.getBean(RequestRejectedHandler.class);}catch (NoSuchBeanDefinitionException ex) {}if (this.requestRejectedHandler != null) { filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);}在中的定义为: private RequestRejectedHandler requestRejectedHandler = new DefaultRequestRejectedHandler();咱们只须要笼罩 Bean 定义即可: @BeanRequestRejectedHandler requestRejectedHandler() { return new CustomizerRequestRejectedHandler();}@Slf4jpublic class CustomizerRequestRejectedHandler implements RequestRejectedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, RequestRejectedException ex) throws IOException, ServletException { log.warn("request uri: {},user-agent: {}", request.getRequestURI(), request.getHeader(HttpHeaders.USER_AGENT)); log.error(ex.getMessage(), ex); response.setStatus(HttpServletResponse.SC_NOT_FOUND); }}参考spring-5-0-3-requestrejectedexception-the-request-was-rejected-because-the-url ...

January 5, 2023 · 1 min · jiezi

关于spring-security:Spring-Security怎么添加图片验证功能

前言Spring security增加图片验证形式,在互联网下面有很多这种博客,都写的十分的具体了。本篇次要讲一些增加图片验证的思路。还有前后端拆散形式,图片验证要怎么去解决? 本章内容图片验证的思路简略的demo思路小白: "咱们从总体流程上看图片验证在认证的哪一个阶段?" 小黑: "在获取客户输出的用户名明码那一阶段,而且要在服务器获取数据库中用户名明码之前。这是一个区间[获取申请用户名明码, 获取数据库用户名明码) 而在 Spring security中, 能够很显著的发现有两种思路。 第1种思路是在拦挡登录申请筹备认证的那个过滤器。第2种思路是在那个过滤器背地的认证器。"小白: "为什么是这个阶段呢? 不能是在判断明码验证之前呢?" 小黑: "你傻啊, 如果在你说的阶段, 服务器须要去数据库中获取用户信息, 这相当的节约系统资源" 小白: "哦哦, 我错了, 让我每每整个流程应该是啥样" 小白: "我须要当时在后端生成一个验证码,而后通过验证码返回一张图片给前端。前端登录表单增加图片验证。用户输出图片验证后点击登录,会寄存在request申请中, 后端须要从request申请中读取到图片验证,判断前后端验证码是否雷同, 如果图片验证码雷同之后才开始从数据库拿用户信息。否则间接抛出认证异样" 简略点: 数据库获取用户账户之前, 先进行图片验证码验证计划怎么将字符串变成图片验证码?这轮子必定不能自己造, 有就拿来吧你 kaptchahutoolkaptcha这么玩<!--验证码生成器--><dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> <exclusions> <exclusion> <artifactId>javax.servlet-api</artifactId> <groupId>javax.servlet</groupId> </exclusion> </exclusions></dependency>@Beanpublic DefaultKaptcha captchaProducer() { Properties properties = new Properties(); properties.put("kaptcha.border", "no"); properties.put("kaptcha.textproducer.char.length","4"); properties.put("kaptcha.image.height","50"); properties.put("kaptcha.image.width","150"); properties.put("kaptcha.obscurificator.impl","com.google.code.kaptcha.impl.ShadowGimpy"); properties.put("kaptcha.textproducer.font.color","black"); properties.put("kaptcha.textproducer.font.size","40"); properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise"); //properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.DefaultNoise"); properties.put("kaptcha.textproducer.char.string","acdefhkmnprtwxy2345678"); DefaultKaptcha kaptcha = new DefaultKaptcha(); kaptcha.setConfig(new Config(properties)); return kaptcha;}@Resourceprivate DefaultKaptcha producer;@GetMapping("/verify-code")public void getVerifyCode(HttpServletResponse response, HttpSession session) throws Exception { response.setContentType("image/jpeg"); String text = producer.createText(); session.setAttribute("verify_code", text); BufferedImage image = producer.createImage(text); try (ServletOutputStream outputStream = response.getOutputStream()) { ImageIO.write(image, "jpeg", outputStream); }}hutool这么玩@GetMapping("hutool-verify-code")public void getHtoolVerifyCode(HttpServletResponse response, HttpSession session) throws IOException { CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 80); session.setAttribute("hutool_verify_code", circleCaptcha.getCode()); response.setContentType(MediaType.IMAGE_PNG_VALUE); circleCaptcha.write(response.getOutputStream());}这俩轻易筛选一个完事前端就非常简单了 ...

January 3, 2023 · 9 min · jiezi

关于spring-security:重新认识Java微服务架构认证服务

前言之前通过浏览《Spring微服务实战》写过对于spring-cloud+spring-security+oauth2的认证服务和资源服务文章,以及写过对于spring-gateway做token校验的文章,然而在实战过程中还是发现一些问题,于是通过跟敌人沟通播种了不了新常识,之前的框架设计有问题,想通过这篇文章从新梳理下校验和认证流程。 遇到的问题1、Feign调用问题:之前所有微服务都做成了资源服务,这样feign调用的时候还要校验token,影响执行效率2、Gateway网关问题:spring-gateway校验了token并把token通过authorization做为申请头下发到上游微服务,上游服务又校验了一遍token,影响执行效率3、全局信息问题:如获取用户信息,微服务api接口通过OAuth2Authentication获取用户名,再通过UserService获取用户信息,这样做再次升高执行效率 如何去解决?综合下面三点问题,提出了绝对应的解决方案: 1、微服务不须要做成资源服务(不须要校验authorization),微服务的权限还有对立解决啥的都在网关里做,这样feign调用的时候也就不须要校验token了。2、下面说过微服务曾经不是资源服务,那么也不存在再次测验token的问题了,尽管如此,然而你能够通过spring-gateway来做对立受权达到管制外界的拜访。3、spring-gateway校验token和封装用户信息到申请头header中,上游服务通过header中的用户信息对立保留到Context中 留神:这里有个问题:A服务有个Controller办法叫saveUserEvent,feign通过/gateway-name/a/saveUserEvent路由调用(feign调用api接口的时候不存在token校验问题),然而没有了资源服务的token限度,里面当然也能够通过gateway调用这个接口,所以这里遇到的问题就是:如何既保证feign的顺利调用又不能让里面申请调用呢?针对这个问题答案是:通过gateway的路由黑名单把不想裸露给里面的api接口排除到路由里面,这样即保障了里面就再也申请不到这个接口了,又保障了服务内通过feign调用的数据安全性。 操作针对下面的三个问题,咱们来从新架构一下咱们的微服务。 1、spring-gateway认证服务操作流程cookie和spring-gateway联合做用户认证服务,这个是通过cookie和set-cookie来达到token传递的成果,前面独自写一篇文章解说。 2、封装用户信息到Context中留神:封装好的Context能够独自放到context包中,并且每个微服务都必须加。 如何来封装呢?其实我代码曾经写好了,大家能够参考应用。UserContext.java @Componentpublic class UserContext { public static final String CORRELATION_ID = "correlation-id"; public static final String AUTH_TOKEN = "authorization"; public static final String USER = "user"; private static final ThreadLocal<String> correlationId = new ThreadLocal<String>(); private static final ThreadLocal<String> authToken = new ThreadLocal<String>(); private static final ThreadLocal<LoginUser> user = new ThreadLocal<>(); public static String getCorrelationId() { return correlationId.get(); } public static void setCorrelationId(String cid) { correlationId.set(cid); } public static String getAuthToken() { return authToken.get(); } public static void setAuthToken(String token) { authToken.set(token); } public static LoginUser getUser() { return user.get(); } public static void setUser(LoginUser u) { user.set(u); } public static HttpHeaders getHttpHeaders() { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.set(CORRELATION_ID, getCorrelationId()); return httpHeaders; }}UserContextFilter.java ...

December 22, 2022 · 2 min · jiezi

关于springsecurity:Spring-Security-Vue-Flowable-怎么玩

@[toc]之前松哥发过一篇文章,和小伙伴们分享了 Spring Boot+Vue+Flowable 的具体玩法,传送门: SpringBoot+Vue+Flowable,模仿一个销假审批流程!不过在那篇文章中,所有波及到用户的中央,都是手动输出的,这显然不太好,例如开启一个销假流程: 这个流程中须要用户输出本人的姓名,其实如果以后用户登录了,就不必输出用户名了,间接就应用以后登录的用户名。 另一方面,当咱们引入了用户零碎之后,当用户提交销假申请的时候,也能够指定审批人,这样看起来就更实在了。 所以,明天咱们就整篇文章,咱们引入 Spring Security,据此来构建用户零碎,一起来看下有了用户零碎的流程引擎该是什么样子。 1. 成果展现货色我曾经做好了,先截个图给大家看下: 这个页面分了三局部: 最下面的是销假申请,用户只须要填入销假天数、销假理由,并且抉择审批人即可,抉择审批人的时候,能够间接指定审批人的名字,也能够抉择审批人的角色,例如抉择经理这个角色,那么未来只有角色为经理的任意用户登录胜利之后,就能够看到本人须要审批的销假了。两头的列表展现以后登录用户已经提交过的销假申请,这些申请的状态分为三种,别离是已通过、已回绝以及待审批。上面的列表是这个用户须要审批的其余用户提交的销假申请,图片中这个用户暂无要审批的工作,如果有的话,这个中央会通过表格展现进去,表格中每一行有批准和回绝两个按钮,点击之后就能够实现本人的操作了。这就是咱们这次要实现的成果了,相比于SpringBoot+Vue+Flowable,模仿一个销假审批流程!文章的案例,这次的显然看起来更像一回事,不过本文的案例是在上篇文章案例的根底上实现的,没看过上篇文章的小伙伴倡议先看下上篇文章,上篇文章中的案例,大家能够在微信公众号江南一点雨的后盾回复 flowable02 获取。 2. 两套用户体系玩过工作流的小伙伴应该都晓得,工作流中其实自带了一套用户零碎,然而咱们本人的零碎往往也有本人的用户体系,那么如何将两者交融起来呢?或者说是否有必要将两者交融起来呢? 如果你想将本人零碎的用户体系和 flowable 中的用户体系交融起来,那么整体上来说,大略就是两种方法吧: 咱们能够以本人零碎中的用户体系为准(因为 flowable 本人的用户体系字段往往不能满足咱们的需要),而后创立对应的视图即可。例如 flowable 中的用户表 ACT_ID_USER、分组表 ACT_ID_GROUP、用户分组关联表 ACT_ID_MEMBERSHIP 等等,把这些和用户体系相干的表删除掉,而后依据这些表的字段和名称,联合本人的零碎用户,创立与之雷同的视图。利用 IdentityService 这个服务,当咱们要操作本人的零碎用户的时候,例如增加、更新、删除用户的时候,顺便调用 IdentityService 服务增加、更新、删除 flowable 中的用户。这两种思路其实都不难,也都很好实现,然而有没有可能咱们就间接舍弃掉 flowable 中的用户体系间接用本人的用户体系呢?在松哥目前的我的项目中,这条路目前是行得通的,就是将 flowable 的用户体系抛到一边,当做没有,只用本人零碎的用户体系。 如果在读这篇文章的小伙伴中,有人在本人的零碎中,有场景必须用到 flowable 自带的用户体系,欢送留言探讨。本文松哥和小伙伴们展现的案例,就是完完全全应用了本人的用户体系,没有用 flowable 中的那一套用户体系。 好啦,这个问题捋分明了,接下来咱们就开搞! 3. 创立用户表首先咱们来创立三张表,别离是用户表 user、角色表 role 以及用户角色关联表 user_role,脚本如下: SET NAMES utf8mb4;DROP TABLE IF EXISTS `role`;CREATE TABLE `role` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `nameZh` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT INTO `role` (`id`, `name`, `nameZh`)VALUES (1,'manager','经理'), (2,'team_leader','组长');DROP TABLE IF EXISTS `user`;CREATE TABLE `user` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT INTO `user` (`id`, `username`, `password`)VALUES (1,'javaboy','{noop}123'), (2,'zhangsan','{noop}123'), (3,'lisi','{noop}123'), (4,'江南一点雨','{noop}123');DROP TABLE IF EXISTS `user_role`;CREATE TABLE `user_role` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `uid` int(11) DEFAULT NULL, `rid` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT INTO `user_role` (`id`, `uid`, `rid`)VALUES (1,1,1), (2,4,1), (3,2,2), (4,3,2);我也大略说下我的用户: ...

August 22, 2022 · 4 min · jiezi

关于spring-security:Spring-Security技术栈开发企业级认证与授权内附文档源码

Spring Security技术栈开发企业级认证与受权内附文档源码下载地址:百度网盘Java 诊断工具 Arthas-实操案例实操案例排查函数调用异样通过curl 请求接口只能看到返回异样,然而看不到具体的请求参数和堆栈信息。shell@Alicloud:~$ curl{"timestamp":1655435063042,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"}复制代码查看UserController的 参数/异样在Arthas里执行:watch com.example.demo.arthas.user.UserController * '{params, throwExp}'复制代码 第一个参数是类名,反对通配第二个参数是函数名,反对通配 拜访watch命令会打印调用的参数和异样再次通过curl 调用可能在arthas外面查看到具体的异样信息。把获取到的后果开展,可能用-x参数:watch com.example.demo.arthas.user.UserController * '{params, throwExp}' -x 2复制代码返回值表达式在下面的例子里,第三个参数是返回值表达式,它实际上是一个ognl表达式,它反对一些内置对象: loaderclazzmethodtargetparamsreturnObjthrowExpisBeforeisThrowisReturn 比如返回一个数组:watch com.example.demo.arthas.user.UserController * '{params[0], target, returnObj}'复制代码条件表达式watch命令反对在第4个参数里写条件表达式,比如:当拜访 user/1 时,watch命令没有输入当拜访 user/101 时,watch会打印出后果。 当异样时捕捉watch命令反对-e选项,示意只捕捉抛出异样时的请求:watch com.example.demo.arthas.user.UserController * "{params[0],throwExp}" -e复制代码按照耗时进行过滤watch命令反对按请求耗时进行过滤,比如:watch com.example.demo.arthas.user.UserController * '{params, returnObj}' '#cost>200'复制代码热更新代码这个也是真的秀。 拜访 http://localhost:61000/user/0 ,会返回500异样:shell@Alicloud:~$ curl http://localhost:61000/user/0{"timestamp":1655436218020,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"}复制代码通过热更新代码,修改这个逻辑。jad反编译UserControllerjad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java复制代码jad反编译的后果保存在 /tmp/UserController.java文件里了。再打开一个Terminal 窗口,而后用vim来编辑/tmp/UserController.java:vim /tmp/UserController.java

August 16, 2022 · 1 min · jiezi

关于springsecurity:SpringSecurityOauth2搭建资源服务

前言之前写过应用springsecurity搭建认证服务SpringSecurity+Oauth2:明码受权模式获取Token(MongoDB+JWT),这篇则写对于如何搭建资源服务,只有验证通过的token能力拜访。 操作1、配置Pom.xml援用spring-cloud-security和oauth2的jar包2、配置主类@EnableResourceServer注解,开启资源服务3、创立JWTTokenStoreConfig类,配置和解析token4、创立ResourceServerConfiguration类配置拜访权限以及自定义异样5、自定义springsecurity异样信息(留神:认证和资源服务的自定义异样是对立的没有区别,上面会阐明) 1、配置Pom.xml援用spring-cloud-security和oauth2的jar包<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> <version>2.2.5.RELEASE</version></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-security</artifactId> <version>2.2.5.RELEASE</version></dependency>2、配置主类@EnableResourceServer注解,开启资源服务@SpringBootApplication// 资源爱护服务@EnableResourceServer// 服务发现@EnableDiscoveryClient@EnableFeignClients@RefreshScopepublic class Xxxx { @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } public static void main(String[] args) { SpringApplication.run(Xxxx.class, args); }}3、创立JWTTokenStoreConfig类,配置和解析token@Configurationpublic class JWTTokenStoreConfig { @Autowired private ServiceConfig serviceConfig; //JWT @Bean public TokenStore tokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } //JWT @Bean @Primary public DefaultTokenServices tokenServices() { DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setTokenStore(tokenStore()); defaultTokenServices.setSupportRefreshToken(true); return defaultTokenServices; } //JWT // 从配置文件中获取jwt key,而后本人解析token是否无效, @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(serviceConfig.getJwtSigningKey()); return converter; }}4、创立ResourceServerConfiguration类配置拜访权限以及自定义异样@Configurationpublic class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{ @Override public void configure(ResourceServerSecurityConfigurer resources) { OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint(); authenticationEntryPoint.setExceptionTranslator(new CustomOAuthWebResponseExceptionTranslator()); resources.authenticationEntryPoint(authenticationEntryPoint); OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler = new OAuth2AccessDeniedHandler(); oAuth2AccessDeniedHandler.setExceptionTranslator(new CustomOAuthWebResponseExceptionTranslator()); resources.accessDeniedHandler(oAuth2AccessDeniedHandler); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 放开/sendRegisterEmailMessage,不须要校验token .antMatchers("/websocket/**").permitAll() .antMatchers("/info/**").permitAll() .anyRequest().authenticated(); }}5、自定义springsecurity异样信息创立CustomOAuthException类 ...

July 18, 2022 · 2 min · jiezi

关于spring-security:Spring-Security-实现动态权限菜单方案附源码

零碎权限治理1、前言在理论开发中,开发任何一套零碎,根本都少不了权限治理这一块。这些足以阐明权限治理的重要性。其实SpringSecurity去年就学了,始终没有工夫整顿,用了一年多工夫了,给我的印象始终都挺好,实用,安全性高(Security能够对明码进行加密)。而且这一块在理论开发中也确实很重要,所以这里整顿了一套基于SpringSecurity的权限治理。 案例代码上面有下载链接。2、案例技术栈如果对于SpringSecurity还不理解的话能够先理解一下SpringSecurity平安控件的学习,页面采纳的是Bootstrap写的(页面就简略的写了一下,能够依据本人的需要更改),其实后端了解了,前台就是显示作用,大家能够自行更换前台页面显示框架,长久层应用的是Spring-Data-Jpa。 并且对后端长久层和控制器进行了一下小封装,Java长久层和控制器的封装。页面应用的Thymeleaf模板,SpringBoot整合Thymeleaf模板。 数据库设计1、表关系 菜单(TbMenu)=====> 页面上须要显示的所有菜单角色(SysRole)=====> 角色及角色对应的菜单用户(SysUser)=====> 用户及用户对应的角色用户和角色两头表(sys_user_role)====> 用户和角色两头表2、数据库表构造菜单表tb_menu 角色及菜单权限表sys_role,其中父节点parent 为null时为角色,不为null时为对应角色的菜单权限。 用户表sys_user 用户和角色多对多关系,用户和角色两头表sys_user_role(有Spring-Data-Jpa主动生成)。 新建我的项目1、新建springboot我的项目新建springboot我的项目,在我的项目中增加SpringSecurity相干Maven依赖,pom.map文件 <?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 https://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.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.mcy</groupId> <artifactId>springboot-security</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot-security</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.webjars.bower</groupId> <artifactId>bootstrap-select</artifactId> <version>2.0.0-beta1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>bootbox</artifactId> <version>4.4.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>2、我的项目构造 ...

July 6, 2022 · 6 min · jiezi

关于springsecurity:SpringSecurity能否吊打Shiro

文章内容:SpringSecurity和Shiro区别及用法 作者:优极限 Apache Shiro是一个弱小且易用的Java平安框架,可能十分清晰的解决认证、受权、治理会话以及明码加密。应用Shiro的易于了解的API,您能够疾速、轻松地取得任何应用程序,从最小的挪动应用程序到最大的网络和企业应用程序。 执行流程 特点易于了解的 Java Security API;简略的身份认证(登录),反对多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);对角色的简略的签权(访问控制),反对细粒度的签权;反对一级缓存,以晋升应用程序的性能;内置的基于 POJO 企业会话治理,实用于 Web 以及非 Web 的环境;异构客户端会话拜访;非常简单的加密 API;不跟任何的框架或者容器捆绑,能够独立运行。Spring Security Spring Security 次要实现了Authentication(认证,解决who are you? ) 和 Access Control(访问控制,也就是what are you allowed to do?,也称为Authorization)。Spring Security在架构上将认证与受权拆散,并提供了扩大点。它是一个轻量级的平安框架,它确保基于Spring的应用程序提供身份验证和受权反对。它与Spring MVC有很好地集成 ,并装备了风行的平安算法实现捆绑在一起。 执行流程 客户端发动一个申请,进入 Security 过滤器链。当到 LogoutFilter 的时候判断是否是登出门路,如果是登出门路则到 logoutHandler ,如果登出胜利则到 logoutSuccessHandler 登出胜利解决,如果登出失败则由 ExceptionTranslationFilter ;如果不是登出门路则间接进入下一个过滤器。当到 UsernamePasswordAuthenticationFilter 的时候判断是否为登录门路,如果是,则进入该过滤器进行登录操作,如果登录失败则到 AuthenticationFailureHandler 登录失败处理器解决,如果登录胜利则到 AuthenticationSuccessHandler 登录胜利处理器解决,如果不是登录申请则不进入该过滤器。当到 FilterSecurityInterceptor 的时候会拿到 uri ,依据 uri 去找对应的鉴权管理器,鉴权管理器做鉴权工作,鉴权胜利则到 Controller 层否则到 AccessDeniedHandler 鉴权失败处理器解决。特点shiro能实现的,Spring Security 根本都能实现,依赖于Spring体系,然而益处是Spring全家桶的亲儿子,集成上更加符合,在应用上,比shiro略负责。 两者比照 Shiro比Spring Security更容易应用,也就是实现上简略一些,同时根本的受权认证Shiro也根本够用 Spring Security社区反对度更高,Spring社区的亲儿子,反对力度和更新保护上有劣势,同时和Spring这一套的联合较好。 ...

January 21, 2022 · 1 min · jiezi

关于springsecurity:spring-securityoauth2-实现统一认证鉴权平台客户端sdk部分

接入简略,反对多租户,可配置,低代码式的疾速实现一套本人的认证鉴权逻辑 蕴含用户治理、部门治理、角色治理、权限治理,将来还能够反对更多模块,比方数据字典治理、... 预计节俭每个利用相干模块研发工夫5人天 对于oauth2.0协定来说,有几个概念 受权服务器客户端资源服务器这偏文章次要讲客户端sdk实现,资源服务器次要就是对立寄存用户信息的,受权服务器应用springsecurity官网的进行小定制。 首先应用springboot的主动配置性能,次要配置类有SecurityConfig,通过编写META-INF/spring.factories来实现主动加载配置bean @Configuration(proxyBeanMethods = false)@EnableWebSecurity@EnableConfigurationProperties(OauthProperties.class)public class SecurityConfig { @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http, IntrospectorFilter filter, CustomLoginUrlAuthenticationEntryPoint entryPoint, ClientRegistrationRepository clientRegistrationRepository, CustomRequestCache customRequestCache) throws Exception { ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests(); if(!CollectionUtils.isEmpty(oauthProperties.getIgnoreUris())) { expressionInterceptUrlRegistry.requestMatchers(oauthProperties.getIgnoreUris().stream().map(AntPathRequestMatcher::new).toArray(RequestMatcher[]::new)).permitAll(); } expressionInterceptUrlRegistry.anyRequest().authenticated().and() .oauth2Login().authorizationEndpoint().authorizationRequestResolver(authorizationRequestResolver(clientRegistrationRepository)) .and() // .defaultSuccessUrl("/", true); .successHandler(authenticationSuccessHandler()); http.oauth2Client().and() .cors().and() .exceptionHandling().authenticationEntryPoint(entryPoint).and() .csrf().disable() .requestCache(requestCacheCustomizer->{ requestCacheCustomizer.requestCache(customRequestCache.getRequestCache(http)); }); http.addFilterBefore(filter, AnonymousAuthenticationFilter.class); return http.build(); } @Bean public CustomRequestCache customRequestCache() { return new CustomRequestCache(); }; private AuthenticationSuccessHandler authenticationSuccessHandler() { SavedRequestAwareAuthenticationSuccessHandler successHandler = new CustomSavedRequestAwareAuthenticationSuccessHandler(); successHandler.setUseReferer(true); return successHandler; } private OAuth2AuthorizationRequestResolver authorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository) { DefaultOAuth2AuthorizationRequestResolver authorizationRequestResolver = new DefaultOAuth2AuthorizationRequestResolver( clientRegistrationRepository, "/oauth2/authorization"); authorizationRequestResolver.setAuthorizationRequestCustomizer( authorizationRequestCustomizer()); return authorizationRequestResolver; } private Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() { return customizer -> customizer .additionalParameters(params -> params.put("tenantId", oauthProperties.getClientId())); } @Bean public CustomLoginUrlAuthenticationEntryPoint customLoginUrlAuthenticationEntryPoint(ObjectMapper objectMapper) { CustomLoginUrlAuthenticationEntryPoint customLoginUrlAuthenticationEntryPoint = new CustomLoginUrlAuthenticationEntryPoint("/oauth2/authorization/auth_server"); customLoginUrlAuthenticationEntryPoint.setObjectMapper(objectMapper); customLoginUrlAuthenticationEntryPoint.setOauthProperties(oauthProperties); return customLoginUrlAuthenticationEntryPoint; }; @Bean public IntrospectorFilter introspectorFilter(OpaqueTokenIntrospector opaqueTokenIntrospector, OAuth2AuthorizedClientService oAuth2AuthorizedClientService) { IntrospectorFilter introspectorFilter = new IntrospectorFilter(); introspectorFilter.setOpaqueTokenIntrospector(opaqueTokenIntrospector); introspectorFilter.setoAuth2AuthorizedClientService(oAuth2AuthorizedClientService); return introspectorFilter; } @Bean public NimbusOpaqueTokenIntrospector opaqueTokenIntrospector() { String introspectUri = oauthProperties.getIssuerUri() + "/oauth2/introspect"; OAuth2ResourceServerProperties.Opaquetoken opaqueToken = new OAuth2ResourceServerProperties.Opaquetoken(); opaqueToken.setIntrospectionUri(introspectUri); opaqueToken.setClientId(oauthProperties.getClientId()); opaqueToken.setClientSecret(oauthProperties.getClientSecret()); return new NimbusOpaqueTokenIntrospector(opaqueToken.getIntrospectionUri(), opaqueToken.getClientId(), opaqueToken.getClientSecret()); } //@RefreshScope 动静刷新 @Bean @ConditionalOnMissingBean public ClientRegistrationRepository clientRegistrationRepository() { return new InMemoryClientRegistrationRepository(this.clientRegistration()); } @Bean public OidcUserService oidcUserService(DefaultOAuth2UserService defaultOAuth2UserService) { CustomOidcUserService oidcUserService = new CustomOidcUserService(); oidcUserService.setAccessibleScopes0(scopes); oidcUserService.setOauth2UserService0(defaultOAuth2UserService); return oidcUserService; } @ConditionalOnMissingBean @Bean public ParameterizedTypeReference<Result<OpenAppUser<Map<String, Object>>>> userInfoTypeReference () { return new ParameterizedTypeReference<Result<OpenAppUser<Map<String, Object>>>>() {}; } @Bean public DefaultOAuth2UserService defaultOAuth2UserService(ParameterizedTypeReference userInfoTypeReference) { CustomDefaultOAuth2UserService defaultOAuth2UserService = new CustomDefaultOAuth2UserService(); defaultOAuth2UserService.setPARAMETERIZED_RESPONSE_TYPE(userInfoTypeReference); return defaultOAuth2UserService; } @Autowired OauthProperties oauthProperties; private Set<String> scopes = new HashSet(){ { //add("openid"); add("user"); } }; private ClientRegistration clientRegistration() { if (oauthProperties.getScopes()!=null) scopes.addAll(oauthProperties.getScopes()); ClientRegistration.Builder auth_server = ClientRegistrations.fromIssuerLocation(oauthProperties.getIssuerUri()).registrationId("auth_server"); return auth_server.clientId(oauthProperties.getClientId()) .clientSecret(oauthProperties.getClientSecret()) .clientName(oauthProperties.getClientName()) //.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) //.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUri((StringUtils.hasText(oauthProperties.getServerUrl())?oauthProperties.getServerUrl():"{baseUrl}")+"/login/oauth2/code/{registrationId}") .scope(scopes) .userInfoUri(oauthProperties.getIssuerUri()+"/client/userinfo") .userNameAttributeName(IdTokenClaimNames.SUB) .build(); }}springsecurity对于oauth2.0的反对还是比较完善的,然而不完全符合咱们对认证受权零碎的要求,所以我这里做了很多自定义,能够说把大部分的拦截器都实现了一些,发现security的代码品质也不是很高,很多中央没有做到扩展性,只能重写类。 ...

November 24, 2021 · 2 min · jiezi

关于spring-security:springsecurity和ObjectMapperjson反序列化的白名单问题记录

这几天在弄一个对立的反对多租户的认证鉴权平台,就想到了应用oauth这种受权协定来进行,通过蕴含open-user信息的jwt来进行散发。应用这个遇到了一些坑,记录如下: 先阐明一下状况,遇到的是fasterxml的json反序列化的白名单问题,因为解决json的框架容易受到攻打,经常出现一些反序列化破绽,新出一个如果采纳黑名单,则这个名单会一直宏大,须要不断更新,故此fasterxml采纳了白名单的机制来实现json反序列化。 这个问题暴发在于应用了OAuth2AuthorizationService这个实现类,外面有new ObjectMapper();咱们不能管制它外面本人new的ObjectMapper,所以咱们必须从新定义一个OAuth2AuthorizationService, @Bean public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository, ObjectMapper objectMapper) { JdbcOAuth2AuthorizationService service = new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository); JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper authorizationRowMapper = new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(registeredClientRepository); authorizationRowMapper.setLobHandler(new DefaultLobHandler()); authorizationRowMapper.setObjectMapper(objectMapper); service.setAuthorizationRowMapper(authorizationRowMapper); return service; }这里注入ObjectMapper,咱们就能对其进行定制化了。 //@Bean 这里能够看状况全局配置objectMapper,如果用到了springmvc,会烦扰到springmvc的json解析//能够把这段写到OAuth2AuthorizationService的Bean定义外面去 public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { return builder -> { //jackson反序列化 平安白名单 builder.mixIn(OpenAppUser.class, OpenAppUserMixin.class); List<Module> securityModules = SecurityJackson2Modules.getModules(LocalDateTimeSerializerConfig.class.getClassLoader()); securityModules.add(new OAuth2AuthorizationServerJackson2Module()); builder.modulesToInstall(securityModules.toArray(new Module[securityModules.size()])); }; }能够去看看这几个Module,外面都是security定义的一些退出平安白名单的类。这里我本人定义了一个用户类,因为登录查问的用户就是应用的这个这样就能够进行自定义用户对象的json平安反序列化了。 //实际上应用security和objectmapper的时候提供了三种形式来实现退出反序列化的白名单,在下面的那个加载Module代码里,首先都会调用SecurityJackson2Modules.enableDefaultTyping(mapper);//办法,而后外面调用mapper.setDefaultTyping(createAllowlistedDefaultTyping());//返回的是一个TypeResolverBuilder,这里的实现类是AllowlistTypeResolverBuilderprivate static TypeResolverBuilder<? extends TypeResolverBuilder> createAllowlistedDefaultTyping() { TypeResolverBuilder<? extends TypeResolverBuilder> result = new AllowlistTypeResolverBuilder( ObjectMapper.DefaultTyping.NON_FINAL); result = result.init(JsonTypeInfo.Id.CLASS, null); result = result.inclusion(JsonTypeInfo.As.PROPERTY); return result; }//AllowlistTypeResolverBuilder类外面的idResolver()办法返回的是TypeIdResolver,实现是一个AllowlistTypeIdResolver()@Overrideprotected TypeIdResolver idResolver(MapperConfig<?> config, JavaType baseType, PolymorphicTypeValidator subtypeValidator, Collection<NamedType> subtypes, boolean forSer, boolean forDeser) { TypeIdResolver result = super.idResolver(config, baseType,subtypeValidator, subtypes, forSer, forDeser); return new AllowlistTypeIdResolver(result);}//重点就是这个类了,它外面的typeFromId办法@Overridepublic JavaType typeFromId(DatabindContext context, String id) throws IOException { DeserializationConfig config = (DeserializationConfig) context.getConfig(); JavaType result = this.delegate.typeFromId(context, id); String className = result.getRawClass().getName(); if (isInAllowlist(className)) { return result; } boolean isExplicitMixin = config.findMixInClassFor(result.getRawClass()) != null; if (isExplicitMixin) { return result; } JacksonAnnotation jacksonAnnotation = AnnotationUtils.findAnnotation(result.getRawClass(), JacksonAnnotation.class); if (jacksonAnnotation != null) { eturn result; } throw new IllegalArgumentException("The class with " + id + " and name of " + className + " is not in the allowlist. " + "If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. " + "If the serialization is only done by a trusted source, you can also enable default typing. " + "See https://github.com/spring-projects/spring-security/issues/4370 for details");}能够看到security提供的这个办法外面的实现,三种形式别离是1.isInAllowlist()是否在这个白名单汇合里2.是否有退出到MixIn,这个就是咱们后面应用的形式3.反序列化类上是否有@JacksonAnnotation注解对于形式1,是个static汇合不能批改;其余两种都能够 ...

November 11, 2021 · 2 min · jiezi

关于spring-security:springsecurity的认证鉴权acloauth20

次要就是一些拦截器链,@PreAuthorize,@PreFilter,@PostAuthorize和@PostFilter 认证AuthenticationManager 基于列表的ProviderManager实现,每个处理器都有机会解决验证胜利或失败 AuthenticationProvider获取适配的处理器 鉴权AccessDecisionManager 基于投票的 AccessDecisionManager 实现,投票决策管理器AccessDecisionVoter 根本实现: RoleVoter投票ROLE_结尾的权限 AuthenticatedVoter用于辨别匿名、齐全身份验证和记住我身份验证的用户 RoleHierarchyVoter层级角色,容许您配置哪些角色admin(或权限)应该包含其余角色user(或权限) AfterInvocationManager 调用后处理,批改平安对象调用理论返回的对象的办法 acl(域对象)访问控制列表 能够应用PermissionEvaluator接口 基于表达式的访问控制 hasPermission(target, permission) boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission);第一种用于拜访被管制的域对象曾经加载的状况。 boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission);第二个版本用于未加载对象但其标识符已知的状况。 旨在表达式零碎和 Spring Security 的 ACL 零碎之间架起桥梁,容许您依据形象权限指定对域对象的受权束缚。它对 ACL 模块没有显式依赖,因而您能够依据须要将其替换为代替实现。 在spring-security-acl.jar里有建表语句,能够开箱即用AclService,AclEntryVoter等类 oauth2协定资源服务器和资源受权服务器 有两个我的项目,spring-security-oauth2和spring-security我的项目下的oauth2模块,目前spring把性能都迁徙到spring-security了,举荐应用spring-security。 spring-security的oauth2.0 客户端反对是通过oauth2Client() DSL(配置,fromLogin那里)办法实现的。资源服务器反对是通过 oauth2ResourceServer() DSL实现的,并且提供了一个OAuth2AuthorizedClientService开箱即用的类。受权服务器目前security还没有集成oauth2.0的,所以只能先用oauth2.0的,应用@EnableAuthorizationServer注解 提供了@RegisteredOAuth2AuthorizedClient注解,将受权的客户端存储在本人的OAuth2AuthorizedClientRepository。 ClientRegistrationRepository来示意客户端,能够通过 Spring Security DSL 提供。或者,这些也能够通过 Spring Boot 进行配置。 能够定义多个SecurityFilterChain,依据matches申请走不同的过滤器链 @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SecurityFilterChain systemSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) .authorizationEndpoint(config->{ OAuth2AuthorizationEndpointConfigurer configurer = (OAuth2AuthorizationEndpointConfigurer) config; }); return http.build(); } @Bean public SecurityFilterChain clientSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests() .requestMatchers(requestMatchers).permitAll() .anyRequest().denyAll().and() .formLogin().and(); return http.build(); }

November 3, 2021 · 1 min · jiezi

关于spring-security:Growing-账号认证实践

背景GrowingIO 作为业余的数据经营解决方案提供商,咱们的客户来自不同的行业,但他们都有雷同的平安需要。在泛滥的客户中,许多客户都有本人的账号认证零碎。因而咱们须要能通过简略的配置接入客户的账号认证零碎。目前 GrowingIO 一共反对了 CAS, OAuth2, LDAP 三种不同的接入协定。本文将具体介绍咱们是如何反对这三个接入形式的。 不同接入协定的认证流程OAuth2一般来说,应用 OAuth2 来实现认证都是应用的受权码模式,咱们这里也不例外,上面是 OAuth2 受权码模式的规范流程。 (A)用户拜访客户端,后者将前者导向认证服务器。 (B)用户抉择是否给予客户端受权。 (C)假如用户给予受权,认证服务器将用户导向客户端当时指定的"重定向URI"(redirection URI),同时附上一个受权码。 (D)客户端收到受权码,附上新近的"重定向 URI ",向认证服务器申请令牌。这一步是在客户端的后盾的服务器上实现的,对用户不可见。 (E)认证服务器核查了受权码和重定向URI,确认无误后,向客户端发送拜访令牌(access token)和更新令牌( refresh token)。 LDAPLDAP 全称 Lightweight Directory Access Protocol,中文名称轻量目录拜访协定。认证登录是其次要利用场景之一,上面是 LDAP 认证的流程。 CASCAS 是一个开源的 Java 服务器组件,给企业提供 Web 单点登录服务,CAS 服务器是构建在 Spring Framework 上的 Java 应用程序,其主要职责是通过颁发和验证票证来验证用户并授予对启用 CAS 的服务(通常称为 CAS 客户端)的拜访权限。当服务器在胜利登录后向用户收回票据授予票据 (TGT) 时,将创立 SSO 会话。服务票证 (ST) 依据用户的申请通过浏览器重定向应用 TGT 作为令牌颁发给服务。ST 随后在 CAS 服务器上通过反向通道通信进行验证。 整体架构 总体思路整体上就是把这三种认证形式都集成到了 OAuth2 受权码模式的流程中,认证核心 IAM 零碎在对接不同的认证协定时表演了不同的角色。 对于账号密码认证, IAM 表演的是 OAuth Server,用户的信息保留在数据库 users 表中,网关Gateway 表演的是 OAuth Client,走的是规范的受权码流程。对于 LDAP 认证,IAM 表演的是 LDAP Client,在认证过程中把用户的用户名和明码拿到 LDAP Server 进行查问,如果查问到非法用户则代表认证胜利,之后再走后续的受权码流程。对于 CAS 认证,IAM表演的是 CAS Client,在获取受权码的接口解决逻辑中,IAM 会检查用户是否认证过,如果没有认证过,会把用户重定向到 CAS Server 去进行认证。在 CAS 的认证回调接口中,依据 ticket 换取用户信息,之后设置用户的认证状态并且生成本人的受权码,前面就是规范的受权码流程。对于 OAuth2 认证,IAM 表演的是 OAuth Client,和 CAS 认证的思路雷同,发现用户没有认证时把用户重定向到 OAuth Server 去进行认证或者受权。在 Oauth Server 的受权码回调接口中,依据返回的受权码拿到 token,进而拿到用户信息,之后设置用户的认证状态并且生成本人的受权码,前面就是规范的受权码流程。登录流程账号密码 & LDAP ...

September 18, 2021 · 3 min · jiezi

关于spring-security:Eurynome-Cloud-Athena-基于Spring-Security-OAuth2-的前后端分离脚手架

Eurynome Cloud Athena 是什么?Eurynome Cloud Athena 是从 Eurynome Cloud 中提取进去的、能够独立运行的、基于OAuth2认证的、前后端拆散的单体式后盾治理脚手架。Eurynome Cloud Athena 实质上就是eurynome-cloud-oauth-starter的利用。从pom中能够看到该工程外围依赖就是Eurynome Cloud 中eurynome-cloud-oauth-starter。Eurynome Cloud Athena 更多的是一个演示性工程,用来示例如何应用eurynome-cloud-oauth-starter,以及相干的配置参数是如何配置的。也能够齐全不必照搬Athena工程,本人新建一个Spring Boot工程,增加eurynome-cloud-oauth-starter依赖和相应的配置也能够应用。Eurynome Cloud Athena 不是什么?Eurynome Cloud Athena 并不是一个残缺的开源我的项目,其外围代码eurynome-cloud-oauth-starter,须要通过编译Eurynome Cloud生成(目前 Eurynome Cloud 外围包并没有提交至Maven地方仓库)。 为什么 Eurynome Cloud Athena 和 Eurynome Cloud 共享代码?不论是独自搭建基于Spring Security OAuth2的后盾治理脚手架,还是构建基于Spring Cloud的散布式微服务架构,Spring Security和OAuth2外围代码的利用形式都是不变的,能够是通用的,因而将Security和OAuth2以及其它通用的代码放在Eurynome Cloud中,编译后供Eurynome Cloud Athena应用。 已经也思考过,在从新提取一个工程,专门搁置通用代码。然而这种形式,额定多了一道编译手续,也不便于对Eurynome Cloud整个代码的理解和应用,因而放弃了这种形式。 为什么构建 Eurynome Cloud Athena?基于Spring Cloud和Spring Cloud Alibaba的微服务架构,曾经成为利用建设的支流计划。然而不可否认的是,搭建一套微服务架构所需的基础架构越来越多,也越来越简单,所需的配套资源也越来越大。仅仅是在开发电脑上搭建一套运行开发调试环境,其复杂度和所需的资源也不容小觑。而很多利用,特地是小型利用,在晚期开发中或者用户量不大的后期齐全没有必要上一整套微服务,额定减少复杂度。很多状况下一套单体的、前后端拆散的后盾就足以满足。 因为以上的思考,才构建的Eurynome Cloud Athena。其实只有Spring Security和OAuth2外围代码写的足够通用,单体式架构就自然而然的产生了。 Eurynome Cloud Athena 不须要搭建Nacos、ELK、Sentinel、Skywalking等基础设施,只有一个数据库就能够独立运行,而且具备微服务架构除服务治理以外的所有性能。不仅编译和运行速度有几倍的晋升,而且只有代码标准、分包正当,能够疾速无缝迁徙到微服务架构。这有助于在我的项目晚期疾速建设项目,不便开发人员在本地进行开发以及技术钻研。 如果你没有大量的工夫和资源搭建微服务架构,那么就能够尝试应用Eurynome Cloud Athena,能够从另一个角度疾速、全面地理解Eurynome Cloud。 我的项目地址后端Gitee地址:https://gitee.com/herodotus/eurynome-cloud后端Github地址:https://github.com/herodotus-cloud/eurynome-cloud

June 30, 2021 · 1 min · jiezi

关于spring-security:记录一次将数据库中密码升级为密文过程

前言改一个老我的项目,老我的项目原来存储明码用的明文,要升级成密文。大略分子工作有两个,一是存储明码时加密,一是将原来数据库中的明码加密。 应用BCryptPasswordEncoder加密BCryptPasswordEncoder是springboot 我的项目中最罕用的明码加密形式,由spring security向咱们提供。咱们首先在配置文件下引入spring security <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency>然而这也会导致一个问题,如果引入这个包的话就会主动启用spring security,再申请的时候就须要用户认证,未认证的用户申请会报403。然而老我的项目并没有应用spring security,而是本人写的登录,手动验证用户名明码。所以我须要敞开spring security作用。在网上查了一下,解决办法是通过在启动类上增加正文去疏忽security无关类。 @SpringBootApplication(exclude = { SecurityAutoConfiguration.class })这个解决形式还有来的及验证,首先在单元测试有问题了。单元测试在测试登录c层时,报错403,这必定是因为security认证没有通过,解决办法是通过在@AutoConfigureMockMvc上退出参数 @AutoConfigureMockMvc(addFilters = false)@AuthConfigureMockMvc负责依赖注入mockMvc,而咱们应用mockMvc进行模仿申请。spring security在校验时通过一条过滤器链,咱们减少addFilters = false使得过滤器不执行,从而不进行认证。这个问题解决了,他的子测试类又报问题了。 @Test public void getById() throws Exception { logger.info("新增一个学院"); College college = collegeService.getOneSavedCollege(); logger.info("获取新增学院,断言胜利"); Long id = college.getId(); mockMvc.perform(get(baseUrl + "/" + id) .cookie(this.cookie)) .andExpect(status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(id)); }他在第7行的mockMvc.perform()报了java.lang.NullPointerException异样,打断点发现是cookie为null,这就是父类通过登录获取cookie,子类通过cookie进行身份认证。然而当初通过测试发现咱们禁用过滤器获取不到cookie了。咱们禁用过滤器是不想让security起作用,然而也造成了获取不到cookie了。我尝试应用其余办法解决禁用security的问题。通过网上给的办法,如退出@WithMockUser,都没有起成果,申请还是报错403。 我只想要BCryptPasswordEncoder,却因为引入他所在的包产生了负影响。询问老师后,老师给出倡议能不能只引入BCryptPasswordEncoder包,在网上找了一番并没有这个包。老师说把BCryptPasswordEncoder类代码复制下来应用,BCryptPasswordEncoder类并没有依赖其余类。引入后,能够失常应用,问题解决。 将生产环境的用户明码明文变密文因为我的项目在生产环境曾经应用一段时间了,认为明码都变成密文了,判断明码形式也变了,咱们也要讲原来用的的明码变为密文,能力不影响用户登录。思路是将所有用户取出来而后明码加密一边而后存回去。要害是如何实现只执行一次。如果明码加密两次必定就不对了。参考老我的项目是通过一个数据库存储后盾版本,而后在启动时判断是否是此版本,如果不是,存储此版本并将明码加密。 @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { String version = "1.0.0"; if (!this.schemaHistoryRepository.findById(version).isPresent()) { this.schemaHistoryRepository.save(new SchemaHistory(version)); List<User> users = this.userRepository.findAll(); for (User user: users) { // 将未加密的数据库中的明码加密 user.setPassword(user.getPassword()); } this.userRepository.saveAll(users); } }BCryptPasswordEncoder在改写setPassword()办法的过程中遇到个问题,因为用户在存储明码时生成一个密文,而后用户登录时前台传给后盾json类型的username和password。后盾通过setPassword()为user赋值,这时前台传来的明码又加密了一编,而BCryptPasswordEncoder雷同数据两次加密后果不一样。导致不能通过判断加密后的明码验证明码谬误与否。这不得不重写一个setPasswordWithEncoder()办法去加密明码,setPassword()办法保留为了接管前台传来的password。这种解决办法使得改起来变得特地凌乱,改单元测试时不晓得用什么办法才对。老师倡议从新建设一个类用于接管前台传来的用户对象 ...

June 12, 2021 · 1 min · jiezi

关于spring-security:spring-security之Secured角色权限

前言写完后盾接口当前,剩下的是退出权限管制。最简略是对于spring security退出的@Secured注解,注解里退出容许拜访的角色即可。 @Secured("ROLE_VIEWER")public String getUsername() { SecurityContext securityContext = SecurityContextHolder.getContext(); return securityContext.getAuthentication().getName();}然而他里边的角色是如何与我定义的用户角色对应的呢,又是对应的哪个字段呢,我也没找到解释,想着写完当前去钻研一下。先写了一个尝试一下,在获取clazz分页数据接口上退出只能管理员拜访,而后登陆一个学生用户,用url跳转到clazz模块,发现起作用了。而后就将大部分接口都退出了@Secured注解。再启动我的项目就发现就不对劲了,他是起作用了,然而对所有角色用户都拦挡了。一开始想到写法不太正确,然而又不晓得外头填的角色名称跟什么绝对应。这能去钻研他的原理。 过程去网上找了很多材料,对于这方面的形容都只停留在应用层面。都是说你只有退出@Secured("ADMIN")注解,就只有你角色是ADMIN的用户能力拜访。然而怎么让用户角色是ADMIN,并没有具体的介绍。网上找不到材料,我问了学长对于原来我的项目的应用办法。学长通知我是因为实现UserDetailsService接口的loadUserByUsername办法里去增加获取到的user的角色。 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { logger.debug("依据用户名查问用户"); User user = this.userRepository.findByUsername(username); if (user == null) { logger.error("用户名不存在"); throw new UsernameNotFoundException("用户名不存在"); } logger.debug("获取用户受权菜单"); Set<Menu> menus = new HashSet<>(); for (Role role : user.getRoles()) { menus.addAll(role.getMenus()); } logger.debug("初始化受权列表"); List<SimpleGrantedAuthority> authorities = new ArrayList<>(); logger.debug("依据菜单进行 API 受权"); for (Menu menu : menus) { authorities.add(new SimpleGrantedAuthority(menu.getRoleName())); } logger.debug("结构用户"); return new YzUserDetail(user, username, user.getPassword(), authorities);}而后与@Secured注解里咱们定义的角色名称绝对应。我一看我的我的项目中loadUserByUsername办法向UserDetail办法传入的authorities参数是一个new ArrayList<>()空数组。我就试着变成传入角色数组,再去试验,还是将所有角色拦挡了。并没有解决问题。而后我在loadUserByUsername办法上打断点,发现看看是否执行,发现只有登录的时候执行了,然而是获取到用户角色了的。我就想可能是其余中央实现的传入角色。我去找哪还用了UserDetail。发现在咱们自定义的spring security过滤器中也使用了, ...

May 9, 2021 · 1 min · jiezi

关于springsecurity:开发SpringBootJwtVue的前后端分离后台管理系统VueAdmin-后端笔记

为了让更多同学学习到前后端拆散管理系统的搭建过程,这里我写了具体的开发过程的文档,应用的是springsecurity + jwt + vue的技术栈组合,如果有帮忙,别忘了点个赞和关注我的公众号哈! 线上预览:https://markerhub.com/vueadmin 效果图: 首发公众号:MarkerHub 作者:吕一明 我的项目源码:关注公众号 MarkerHub 回复【 234 】获取 线上预览:https://markerhub.com/vueadmin 我的项目视频:https://www.bilibili.com/video/BV1af4y1s7Wh/ 转载请保留此申明,感激! 另外我还有另外一个前后端博客我的项目博客VueBlog,如果有须要能够关注公众号MarkerHub,回复【VueBlog】获取哈!! 1. 前言从零开始搭建一个我的项目骨架,最好抉择适合相熟的技术,并且在将来易拓展,适宜微服务化体系等。所以个别以Springboot作为咱们的框架根底,这是离不开的了。 而后数据层,咱们罕用的是Mybatis,易上手,不便保护。然而单表操作比拟艰难,特地是增加字段或缩小字段的时候,比拟繁琐,所以这里我举荐应用Mybatis Plus(https://mp.baomidou.com/),... CRUD 操作,从而节俭大量工夫。 作为一个我的项目骨架,权限也是咱们不能疏忽的,上一个我的项目vueblog咱们应用了shiro,然而有些同学想学学SpringSecurity,所以这一期咱们应用security作为咱们的权限管制和会话管制的框架。 思考到我的项目可能须要部署多台,一些须要共享的信息就保留在中间件中,Redis是当初支流的缓存中间件,也适宜咱们的我的项目。 而后因为前后端拆散,所以咱们应用jwt作为咱们用户身份凭证,并且session咱们会禁用,这样以前传统我的项目应用的形式咱们可能就不再适宜应用,这点须要留神了。 ok,咱们当初就开始搭建咱们的我的项目脚手架! 技术栈: SpringBootmybatis plusspring securitylombokredishibernate validatiorjwt2. 新建springboot我的项目,留神版本这里,咱们应用IDEA来开发咱们我的项目,新建步骤比较简单,咱们就不截图了。 开发工具与环境: ideamysqljdk 8maven3.3.9新建好的我的项目构造如下,SpringBoot版本应用的目前最新的2.4.0版本 pom的jar包导入如下: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.0</version> <relativePath/></parent><groupId>com.markerhub</groupId><artifactId>vueadmin-java</artifactId><version>0.0.1-SNAPSHOT</version><name>vueadmin-java</name><description>公众号:MarkerHub</description><properties> <java.version>1.8</java.version></properties><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency></dependencies>devtools:我的项目的热加载重启插件lombok:简化代码的工具3. 整合mybatis plus,生成代码接下来,咱们来整合mybatis plus,让我的项目能实现根本的增删改查操作。步骤很简略:能够去官网看看:https://mp.baomidou.com/guide/ 第一步:导入jar包pom中导入mybatis plus的jar包,因为前面会波及到代码生成,所以咱们还须要导入页面模板引擎,这里咱们用的是freemarker。 <!--整合mybatis plus https://baomidou.com/--><dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version></dependency><!--mp代码生成器--><dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.1</version></dependency><dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency>第二步:而后去写配置文件server: port: 8081# DataSource Configspring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/vueadmin?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: adminmybatis-plus: mapper-locations: classpath*:/mapper/**Mapper.xml下面除了配置数据库的信息,还配置了myabtis plus的mapper的xml文件的扫描门路,这一步不要遗记了。而后因为前段默认是8080端口了,所以后端咱们设置为8081端口,避免端口抵触。 ...

April 29, 2021 · 14 min · jiezi

关于springboot:一security之环境要求和数据库配置说明

一、环境要求: jdk8 、装置了且配置了maven 、装置了msql 二、我的项目代码 1、导入依赖<dependency> <groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency> emm ,导入依赖后间接启动拜访接口会弹出一个表单要你输出,用户名为:user 明码为:在控制台看 2、创立数据库员工信息库CREATE TABLE tb_sys_employee (id varchar(20) NOT NULL COMMENT '员工id',name varchar(100) NOT NULL COMMENT '实在姓名',phone varchar(50) NOT NULL COMMENT '电话号码',card varchar(20) NOT NULL COMMENT '身份证号码',password varchar(40) NOT NULL COMMENT '明码(密文)',code varchar(64) NOT NULL COMMENT '工号',status tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态0 停用 1:启用',nick_name varchar(100) NOT NULL COMMENT '工号名称',salt varchar(8) NOT NULL COMMENT '盐',address varchar(64) DEFAULT NULL COMMENT '住址',create_name varchar(64) DEFAULT NULL COMMENT '创建人',create_time datetime DEFAULT NULL COMMENT '创立工夫',update_time datetime DEFAULT NULL COMMENT '更新工夫',role int(6) DEFAULT '1' COMMENT '1 admin 2、employee 4、user',avatar varchar(256) DEFAULT NULL COMMENT '头像', PRIMARY KEY (id) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='员工表'; ...

April 23, 2021 · 2 min · jiezi

关于spring-security:spring-security-oAuth2

@Controller与@RestController@Controller与@RestController的区别1 后者不能返回jsp页面,  @RestController是@Controller和@ResponseBody的结合体,两个标注合并起来的作用。2、如果只是应用@RestController注解Controller,则Controller中的办法无奈返回jsp页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。 例如:原本应该到success.jsp页面的,则其显示success. 3、如果须要返回到指定页面,则须要用 @Controller配合视图解析器InternalResourceViewResolver才行。 4、如果须要返回JSON,XML或自定义mediaType内容到页面,则须要在对应的办法上加上@ResponseBody注解。

January 21, 2021 · 1 min · jiezi

关于spring-security:SpringBootSpringSecurityJWT整合实现单点登录SSO史上最全详解

欢送微信搜寻公众号【java版web我的项目】获取资源:java学习视频/设计模式笔记/算法手册/java我的项目 一、什么是单点登陆 单点登录(Single Sign On),简称为 SSO,是目前比拟风行的企业业务整合的解决方案之一。SSO的定义是在多个利用零碎中,用户只须要登录一次就能够拜访所有相互信任的利用零碎 二、简略的运行机制 单点登录的机制其实是比较简单的,用一个事实中的例子做比拟。某公园外部有许多独立的景点,游客能够在各个景点门口独自买票。对于须要玩耍所有的景点的游客,这种买票形式很不不便,须要在每个景点门口排队买票,钱包拿 进拿出的,容易失落,很不平安。于是绝大多数游客抉择在大门口买一张通票(也叫套票),就能够玩遍所有的景点而不须要从新再买票。他们只须要在每个景点门 口出示一下方才买的套票就可能被容许进入每个独立的景点。单点登录的机制也一样,如下图所示, 用户认证:这一环节次要是用户向认证服务器发动认证申请,认证服务器给用户返回一个胜利的令牌token,次要在认证服务器中实现,即图中的认证零碎,留神认证零碎只能有一个。身份校验:这一环节是用户携带token去拜访其余服务器时,在其余服务器中要对token的真伪进行测验,次要在资源服务器中实现,即图中的利用零碎2 3 三、JWT介绍概念阐明 从分布式认证流程中,咱们不难发现,这两头起最关键作用的就是token,token的平安与否,间接关系到零碎的健壮性,这里咱们抉择应用JWT来实现token的生成和校验。 JWT,全称JSON Web Token,官网地址https://jwt.io,是一款杰出的分布式身份校验计划。能够生成token,也能够解析测验token。 JWT生成的token由三局部组成:头部:次要设置一些标准信息,签名局部的编码格局就在头部中申明。载荷:token中寄存无效信息的局部,比方用户名,用户角色,过期工夫等,然而不要放明码,会泄露!签名:将头部与载荷别离采纳base64编码后,用“.”相连,再退出盐,最初应用头部申明的编码类型进行编码,就失去了签名。 JWT生成token的安全性剖析 从JWT生成的token组成上来看,要想防止token被伪造,次要就得看签名局部了,而签名局部又有三局部组成,其中头部和载荷的base64编码,简直是通明的,毫无安全性可言,那么最终守护token平安的重任就落在了退出的盐下面了!试想:如果生成token所用的盐与解析token时退出的盐是一样的。岂不是相似于中国人民银行把人民币防伪技术公开了?大家能够用这个盐来解析token,就能用来伪造token。这时,咱们就须要对盐采纳非对称加密的形式进行加密,以达到生成token与校验token方所用的盐不统一的平安成果! 非对称加密RSA介绍基本原理:同时生成两把密钥:私钥和公钥,私钥隐秘保留,公钥能够下发给信赖客户端私钥加密,持有私钥或公钥才能够解密公钥加密,持有私钥才可解密长处:平安,难以破解毛病:算法比拟耗时,为了平安,能够承受历史:三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,能够实现非对称加密。这种算法用他们三个人的名字缩写:RSA。 四、SpringSecurity整合JWT1.认证思路剖析 SpringSecurity次要是通过过滤器来实现性能的!咱们要找到SpringSecurity实现认证和校验身份的过滤器! 回顾集中式认证流程用户认证: 应用UsernamePasswordAuthenticationFilter过滤器中attemptAuthentication办法实现认证性能,该过滤器父类中successfulAuthentication办法实现认证胜利后的操作。身份校验: 应用BasicAuthenticationFilter过滤器中doFilterInternal办法验证是否登录,以决定是否进入后续过滤器。 剖析分布式认证流程用户认证: 因为分布式我的项目,少数是前后端拆散的架构设计,咱们要满足能够承受异步post的认证申请参数,须要批改UsernamePasswordAuthenticationFilter过滤器中attemptAuthentication办法,让其可能接管申请体。 另外,默认successfulAuthentication办法在认证通过后,是把用户信息间接放入session就完事了,当初咱们须要批改这个办法,在认证通过后生成token并返回给用户。身份校验: 原来BasicAuthenticationFilter过滤器中doFilterInternal办法校验用户是否登录,就是看session中是否有用户信息,咱们要批改为,验证用户携带的token是否非法,并解析出用户信息,交给SpringSecurity,以便于后续的受权性能能够失常应用。 2.具体实现 为了演示单点登录的成果,咱们设计如下我的项目构造 2.1父工程创立 因为本案例须要创立多个零碎,所以咱们应用maven聚合工程来实现,首先创立一个父工程,导入springboot的父依赖即可 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/></parent>1234562.2公共工程创立 而后创立一个common工程,其余工程依赖此零碎导入JWT相干的依赖 <dependencies> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.10.7</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.10.7</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.10.7</version> <scope>runtime</scope> </dependency> <!--jackson包--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.9</version> </dependency> <!--日志包--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency></dependencies>123456789101112131415161718192021222324252627282930313233343536373839404142创立相干的工具类 ...

January 6, 2021 · 9 min · jiezi

关于springsecurity:Spring-Security-之学习路途

Spring Security 学习之旅开始SpringSecurity 开始我的项目:Github 1. 引入依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.1</version> <relativePath/> </parent> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>在manven依赖仓库中: 2. 配置Security1.在包下创立SecurityCconfig类,重写configure办法,其中WebSecurity web,能够定义疏忽门路 @Override public void configure(WebSecurity web) throws Exception { //疏忽拦挡 web.ignoring().antMatchers("/sayHello","/doLogin"); }HttpSecurity http 能够拦挡申请,能够定义登录、登出等等 @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests()//开启登录 //示意拜访,ex/index 这个接口,须要具备admin角色 .antMatchers("/es/**").hasRole("admin") //示意残余的其余接口,登录之后能拜访 .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") //登录解决接口 .loginProcessingUrl("/doLogin") //定义登录时,用户名的key,默认为username .usernameParameter("username") //定义登录时,用户明码的key,默认为password .passwordParameter("password") //定义登录胜利的处理器 .successHandler(new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); response.sendRedirect("/success.html");//重定向到一个页面 MyUserDetails detail= (MyUserDetails)authentication.getPrincipal(); System.out.println(detail); } }) .failureHandler(new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); ResponseBean responseBean = ResponseBean.sendByCode("you have login failure !", 401); String result = new ObjectMapper().writeValueAsString(responseBean); out.write(result); out.flush(); } }) //和表单登录相干的接口通通都间接通过 .permitAll() .and() .logout() .logoutUrl("/logout") .logoutSuccessHandler(new LogoutSuccessHandler() { @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); out.write("you have login out success !"); out.flush(); } }) .permitAll() .and() .httpBasic() .and() .csrf().disable(); }简略的表单登录配置,这里的logou是Get申请,若要Post申请,则减少一行 ...

December 29, 2020 · 3 min · jiezi

关于spring-security:Spring-Cloud-Spring-Security实践五-整合验证码功能

此处应用kaptcha依赖实现图形验证码校验性能 引入依赖<dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version></dependency>Kaptcha 相干配置配置kaptcha实例 @Beanpublic Producer captcha() { // 配置图形验证码的基本参数 Properties properties = new Properties(); // 图片宽度 properties.setProperty("kaptcha.image.width", "150"); // 图片长度 properties.setProperty("kaptcha.image.height", "50"); // 字符集 properties.setProperty("kaptcha.textproducer.char.string", "0123456789"); // 字符长度 properties.setProperty("kaptcha.textproducer.char.length", "4"); Config config = new Config(properties); // 应用默认的图形验证码实现,当然也能够自定义实现 DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); defaultKaptcha.setConfig(config); return defaultKaptcha;}配置kaptcha路由 @Controllerpublic class CaptchaController { @Autowired private Producer captchaProducer; @GetMapping("/captcha.jpg") public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException { // 设置内容类型 response.setContentType("image/jpeg"); // 创立验证码文本 String capText = captchaProducer.createText(); // 将验证码文本设置到session request.getSession().setAttribute("captcha", capText); // 创立验证码图片 BufferedImage bi = captchaProducer.createImage(capText); // 获取响应输入流 ServletOutputStream out = response.getOutputStream(); // 将图片验证码数据写到响应输入流 ImageIO.write(bi, "jpg", out); // 推送并敞开响应输入流 try { out.flush(); } finally { out.close(); } }}在security config办法中对所有kaptcha申请放行 ...

November 2, 2020 · 2 min · jiezi

关于spring-security:springBoot整合spring-security实现权限管理单体应用版筑基初期

写在后面在后面的学习当中,咱们对spring security有了一个小小的意识,接下来咱们整合目前的支流框架springBoot,实现权限的治理。 在这之前,假设你曾经理解了基于资源的权限治理模型。数据库设计的表有 user 、role、user_role、permission、role_permission。 步骤:默认大家都曾经数据库曾经好,曾经有了下面提到的表。(文末提供sql脚本下载) 第一步:在pom.xml文件中引入相干jar包<?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 https://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.3.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>pers.lbf</groupId> <artifactId>springboot-spring-securioty-demo1</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot-spring-security-demo1</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>第二步:批改application.yml文件,增加数据库相干配置server: port: 8081spring: datasource: url: jdbc:mysql://127.0.0.1:3306/secutiry_authority?useSSL=false&serverTimezone=GMT username: root password: root1997 driver-class-name: com.mysql.cj.jdbc.Driver第三步:启动我的项目springboot曾经给咱们提供好了一个默认的username为“user”,其明码能够在控制台输入中失去。并且在springBoot的默认配置中,所有资源必须要通过认证后能力拜访 ...

October 14, 2020 · 4 min · jiezi

关于spring-security:Spring-Security学习笔记一

1 Spring Security1.1 简介Spring Security是一个弱小和高度可定制的认证和管制拜访框架,是基于Spring利用的事实上的平安规范,次要聚焦于为Java利用提供受权和认证性能,次要性能如下: 对认证和受权的全面和可扩大反对避免诸如Session Fixation、点击劫持、跨站点申请伪造攻打Servlet API集成Spring MVC可全集成1.2 已集成的认证技术HTTP BASIC authentication headers/HTTP Digest authentication headers/HTTP X.509 client certificate exchange:基于IETF RFC的规范LDAP:常见的跨平台身份验证形式Form-based authentication:用于简略的用户界面需要OpenID authentication:一种去中心化的身份认证形式Authentication based on pre-established request headers:一种用户身份验证以及受权的集中式平安根底计划Jasig Central Authentication Service:单点登录计划Transparent authentication context propagation for Remote Method Invocation and HttpInvoker:一个Spring近程调用协定Automatic "remember-me" authentication:容许在指定到期工夫前自行从新登录零碎Anonymous authentication:容许匿名用户应用特定身份平安拜访资源Run-as authentication:容许在一个会话中变换用户身份的机制Java Authentication and Authorization:JASS,Java验证和受权APIJava EE container authentication:容许零碎持续应用容器治理这种身份验证形式Kerberos:一种应用对称密钥机制,容许客户端和服务器互相确认身份的认证协定除此之外还引入了其余第三方包,比方JOSSO,另外如果都无奈满足需要,Spring Security也容许开发人员本人编写认证技术。 2 简略Demo上面来动手做一个简略的Demo去体验一下Spring Security。 2.1 新建工程 默认即可: 依赖抉择Spring Web和Spring Secutiry: 2.2 启动类批改启动类,使其作为Controller类: @SpringBootApplication@RestControllerpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @GetMapping("/") public String hello(){ return "Hello, Spring Security."; }}2.3 运行运行后能够看见控制台有一串主动生成的明码: ...

October 13, 2020 · 1 min · jiezi

关于spring-security:Spring-Security一Simple-Demo

Simple Demo该系列都是基于前后端拆散的形式,返回的数据都是应用的 JSON,以及应用了自定义的返回后果 starter:https://gitee.com/lin-mt/result-spring-boot。 源码地址:https://gitee.com/lin-mt/spring-boot-examples/tree/master/spring-security-data-permission-control新建一个 SpringBoot 我的项目,引入相干依赖<dependency> <artifactId>spring-boot-starter-data-jpa</artifactId> <groupId>org.springframework.boot</groupId></dependency><dependency> <artifactId>spring-boot-starter-security</artifactId> <groupId>org.springframework.boot</groupId></dependency><dependency> <artifactId>spring-boot-starter-web</artifactId> <groupId>org.springframework.boot</groupId></dependency><dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId></dependency><dependency> <artifactId>mysql-connector-java</artifactId> <groupId>mysql</groupId> <scope>runtime</scope></dependency><dependency> <groupId>com.gitee.lin-mt</groupId> <artifactId>result-spring-boot-starter</artifactId></dependency>自定义用户信息/** * 用户信息. * * @author <a href="mailto:lin-mt@outlook.com">lin-mt</a> */@Entity@Table(name = "sys_user")public class SysUser extends BaseEntity implements UserDetails, CredentialsContainer { private String username; @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) private String secretCode; private int accountNonExpired; private int accountNonLocked; private int credentialsNonExpired; private int enabled; @Transient private Collection<? extends GrantedAuthority> authorities; // setter and getter @Basic @Override @Column(name = "username") public String getUsername() { return username; } @Override @Transient @JsonIgnore public String getPassword() { return getSecretCode(); } @Override @Transient public boolean isAccountNonExpired() { return 0 == this.accountNonExpired; } @Override @Transient public boolean isAccountNonLocked() { return 0 == this.accountNonLocked; } @Override @Transient public boolean isCredentialsNonExpired() { return 0 == this.credentialsNonExpired; } @Override @Transient public boolean isEnabled() { return 1 == this.enabled; } @Override public void eraseCredentials() { this.secretCode = null; } @Override public String toString() { return "SysUser{" + "username='" + username + '\'' + ", gender='" + gender + '\'' + ", phoneNumber='" + phoneNumber + '\'' + ", emailAddress='" + emailAddress + '\'' + ", accountNonExpired=" + accountNonExpired + ", accountNonLocked=" + accountNonLocked + ", credentialsNonExpired=" + credentialsNonExpired + ", enabled=" + enabled + ", authorities=" + authorities + '}'; }}为什么要实现接口 org.springframework.security.core.userdetails.UserDetails 呢?首先,Spring Security 必定须要依据用户输出的某个条件(通常是用户名,也就是 username )获取该条件对应的用户信息,而后再依据登录人输出的信息以及对应的用户信息去验证是否可能登录零碎。那么 Spring Security 怎么能力从用户信息中获取验证所须要的数据呢,用户信息是咱们返回给 Spring Security 的,无论是从内存还是数据库获取,都是包装成一个实体。重点来了,如果这个实体实现了某个接口,那么就能够将该实体向上转型为该接口的实体(这是 Java 根底哈),这时候就能够间接调用实体中接口的办法获取实体的数据!而后就能够依据这些数据验证登录人能不能进入零碎了,所以 UserDetails 接口中咱们要实现的几个办法中,返回的数据就是 Spring Security 用来验证的数据。 ...

August 16, 2020 · 4 min · jiezi

关于spring-security:Spring-Security一Simple-Demo

Simple Demo该系列都是基于前后端拆散的形式,返回的数据都是应用的 JSON,以及应用了自定义的返回后果 starter:https://gitee.com/lin-mt/result-spring-boot。 源码地址:https://gitee.com/lin-mt/spring-boot-examples/tree/master/spring-security-data-permission-control新建一个 SpringBoot 我的项目,引入相干依赖<dependency> <artifactId>spring-boot-starter-data-jpa</artifactId> <groupId>org.springframework.boot</groupId></dependency><dependency> <artifactId>spring-boot-starter-security</artifactId> <groupId>org.springframework.boot</groupId></dependency><dependency> <artifactId>spring-boot-starter-web</artifactId> <groupId>org.springframework.boot</groupId></dependency><dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId></dependency><dependency> <artifactId>mysql-connector-java</artifactId> <groupId>mysql</groupId> <scope>runtime</scope></dependency><dependency> <groupId>com.gitee.lin-mt</groupId> <artifactId>result-spring-boot-starter</artifactId></dependency>自定义用户信息/** * 用户信息. * * @author <a href="mailto:lin-mt@outlook.com">lin-mt</a> */@Entity@Table(name = "sys_user")public class SysUser extends BaseEntity implements UserDetails, CredentialsContainer { private String username; @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) private String secretCode; private int accountNonExpired; private int accountNonLocked; private int credentialsNonExpired; private int enabled; @Transient private Collection<? extends GrantedAuthority> authorities; // setter and getter @Basic @Override @Column(name = "username") public String getUsername() { return username; } @Override @Transient @JsonIgnore public String getPassword() { return getSecretCode(); } @Override @Transient public boolean isAccountNonExpired() { return 0 == this.accountNonExpired; } @Override @Transient public boolean isAccountNonLocked() { return 0 == this.accountNonLocked; } @Override @Transient public boolean isCredentialsNonExpired() { return 0 == this.credentialsNonExpired; } @Override @Transient public boolean isEnabled() { return 1 == this.enabled; } @Override public void eraseCredentials() { this.secretCode = null; } @Override public String toString() { return "SysUser{" + "username='" + username + '\'' + ", gender='" + gender + '\'' + ", phoneNumber='" + phoneNumber + '\'' + ", emailAddress='" + emailAddress + '\'' + ", accountNonExpired=" + accountNonExpired + ", accountNonLocked=" + accountNonLocked + ", credentialsNonExpired=" + credentialsNonExpired + ", enabled=" + enabled + ", authorities=" + authorities + '}'; }}为什么要实现接口 org.springframework.security.core.userdetails.UserDetails 呢?首先,Spring Security 必定须要依据用户输出的某个条件(通常是用户名,也就是 username )获取该条件对应的用户信息,而后再依据登录人输出的信息以及对应的用户信息去验证是否可能登录零碎。那么 Spring Security 怎么能力从用户信息中获取验证所须要的数据呢,用户信息是咱们返回给 Spring Security 的,无论是从内存还是数据库获取,都是包装成一个实体。重点来了,如果这个实体实现了某个接口,那么就能够将该实体向上转型为该接口的实体(这是 Java 根底哈),这时候就能够间接调用实体中接口的办法获取实体的数据!而后就能够依据这些数据验证登录人能不能进入零碎了,所以 UserDetails 接口中咱们要实现的几个办法中,返回的数据就是 Spring Security 用来验证的数据。 ...

August 16, 2020 · 4 min · jiezi