最近写了几个SpringBoot组件,针对项目的功能引入了相应的依赖,配置好就可以使用了,这很香!那么SpringSecurity是不是也可以做成模块化,简单配置就可以使用呢?JWT一定要有,RBAC动态权限一定要有!花了半天时间写了一个组件,用了一个月感觉不错。我一个人好玩吗?还是放出来大家一起欣赏?经过一个月的反复思想斗争,我终于做出了一个明智的决定,将它发布给想要直接上手的同学。源码地址如下:https://gitee.com/felord/security-enhance-spring-bootusageintegration这是一个SpringBootStarter,大家自己打包安装。然后引用项目:cn.felord.securitysecurity-enhance-spring-boot-starter${version}另外需要集成SpringCache,比如RedisCache:org.springframework.bootspring-boot-starter-cacheorg.springframework.bootspring-boot-starter-data-redisorg.apache.commonscommons-pool2JWT会以usrTkn为key缓存在缓存中。如果你想自定义它,你可以实现一个JwtTokenStorage并注入SpringIoC来覆盖以下配置:@Bean@ConditionalOnMissingBeanpublicJwtTokenStoragejwtTokenStorage(){returnnewSpringCacheJwtTokenStorage();}你应该学习如何自定义SpringCache的过期时间。数据库表设计再数据库表设计,这里先做一个简单的RBAC设计,仅供参考,大家可以根据自己的业务进行改进。用户表:user_id用户名密码1312434534felord{noop}12345角色表:role_idrole_namerole_code12343667867AdministratorADMIN用户角色关联表:user_role_iduser_idrole_id123546577771312434534128647367在一个字符集中唯一。资源表:resources_idresources_nameresource_patternmethod12543667867通过ID获取商品/goods/{goodsId}GET资源其实就是我们写的SpringMVC接口,支持ANT风格,但是尽量具体。出于灵活性考虑,不建议使用通配符。角色资源表:role_res_idrole_idresources_id45454664451234366786712543667867一个资源可以关联多个角色,一个角色不能重复持有一个资源。ImplementingUserDetailsS??ervice实现用户加载服务接口UserDetailsS??ervice是SpringSecurity开发的必经步骤,和我之前的教程差不多。@OverridepublicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException{UserInfouserInfo=this.lambdaQuery().eq(UserInfo::getUsername,username).one();if(Objects.isNull(userInfo)){thrownewUsernameNotFoundException("User:"+username+"不存在");}StringuserId=userInfo.getUserId();booleanenabled=userInfo.getEnabled();Setroles=iUserRoleService.getRolesByUserId(userId);roles.add(""ANONYMOUS"");SetroleSet=roles.stream().map(role->newSimpleGrantedAuthority("ROLE_"+role)).collect(Collectors.toSet());returnnewSecureUser(userId,username,userInfo.getSecret(),enabled,enabled,enabled,enabled,roleSet);}这里想说说为什么要给用户内置一个ANONYMOUS角色。如果希望某个特定的资源对用户完全开放,可以将相应的权限角色代码配置为ANONYMOUS。当资源的角色代码为ANONYMOUS时,即使不携带Token也可以访问。一般情况下,可以匿名访问的资源,如果不是匿名的,一定是可以访问的。当然,如果你不想让这样的规则存在,干脆杀掉它们。查询用户的权限集实现用户角色权限方法功能配置是最后一个配置,和我之前教程的配置差不多。application.yaml的配置是:#jwt配置jwt:cert-info:#keytoolkeyaliasalias:felord#Keypasswordkey-password:i6x123akg15v13#这里的路径在资源包下cert-location:jwt.jksclaims:#jwtiss字段valueissuer:https://felord.cn#subfieldsubject:all#expiredsecondsexpires-at:604800最后别忘了做一个配置类,标记@EnableSpringSecurity开启配置:@EnableSpringSecurity@Configuration(proxyBeanMethods=false)publicclassSecurityConfiguration{/***Functionfunction.**@paramresourcesServicetheresourcesservice*@returnthefunction*/@BeanFunction,Set>function(IResourcesServiceresourcesService){returnresourcesService::matchers;}@BeanUserDetailsS??erviceuserDetailsS??ervice(IUserInfoServiceuserInfoService){returnuserInfoService::loadUserByUsername;}}请记住使用@EnableCaching来启用和配置缓存。使用登录接口POST/login?username=felord&password=12345HTTP/1.1Host:localhost:8080然后返回一对JWT,其中包含两个token。accessToken用于日常请求认证,有过期时间。refreshToken用于在accessToken过期时刷新accessToken。结构是:{"accessToken":{"tokenValue":"","issuedAt":{"epochSecond":1616827822,"nano":393000000},"expiresAt":{"epochSecond":1616831422,"nano":393000000},"tokenType":{"value":"Bearer"},"scopes":["ROLE_ADMIN","ROLE_ANONYMOUS"]},"refreshToken":{"tokenValue":"","issuedAt":{"epochSecond":1616827822,"nano":393000000},"expiresAt":null},"additionalParameters":{}}调用接口获取商品ID时添加Token:GET/goods/234355451HTTP/1.1Host:localhost:8080Authorization:BearereyJraWQImFsZyI6IlJTMjU2In0eyJzdWIiOiJ1NzgsImlhdCI6MTYxNjkxODk3OCwianRpIjoiNThlOTQktNGVlYzc3MDU0ZDk3In0.ZQcN0FX7_taohqPiC1KnoF7本文转载自微信“NodecanfollowyouXiaopongcode♂”,转载本文请联系码农小胖公众号。