SpringSecurity
整合OAuth2
是开发者公认的资源保护
、服务认证
的最佳搭配伙伴,这对好基友一直在默默的守护着应用服务的安全,根据访问者的不一样角色能够颗粒度控制到具体的接口,从而实现权限的细微划分。html
而SpringSecurity
框架在安全框架的队伍中算是入门比较高的,虽然Spring
经过SpringBoot
进行了封装,可是使用起来仍是有不少容易遗漏的配置,由于配置比较多,让初学者理解起来也比较困难,针对这个问题ApiBoot
对SpringSecurity
以及OAuth2
进行了封装,在基础上极大的简化了配置(只作简化、加强,SpringSecurity
的基础语法、配置还能够正常使用)java
使用IDEA
开发工具建立一个SpringBoot
项目。mysql
ApiBoot
的底层是SpringBoot
,并且ApiBoot
为了支持SpringBoot
的2.2.x
分支,也对应的建立了2.2.x
分支版本。
建立完项目后咱们须要在pom.xml
添加ApiBoot
的统一版本依赖,以下所示:程序员
<dependencyManagement> <dependencies> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-dependencies</artifactId> <version>2.2.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
本章咱们须要查询数据库内的用户信息进行认证,因此须要在pom.xml
添加数据库相关的依赖,以下所示:web
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-starter-security-oauth-jwt</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-starter-mybatis-enhance</artifactId> </dependency> </dependencies>
在本章使用到了ApiBoot Mybatis Enhance
,具体的使用请访问官方文档ApiBoot MyBatis Enhance使用文档spring
添加数据库相关的依赖后,在application.yml
文件内添加以下配置信息:sql
spring: application: name: apiboot-security-oauth-custom-certification-user # 数据源配置 datasource: type: com.zaxxer.hikari.HikariDataSource url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver server: port: 9090
ApiBoot Security
默认采用的是内存方式
(memory)读取用户信息,咱们本章须要修改成JDBC
方式,而且禁用默认读取用户信息
(ApiBoot Security
内部提供了默认的表结构,建表后添加数据便可直接使用用户信息进行认证,详见:ApiBoot Security使用文档)。数据库
在application.yml
配置文件中添加以下配置:json
# ApiBoot配置 api: boot: security: # ApiBoot Security 使用JDBC方式读取用户 away: jdbc # 禁用默认的读取用户方式 enable-default-store-delegate: false
api.boot.security.enable-default-store-delegate
配置参数默认值为true
,也就是会自动读取数据源对应数据库内的api_boot_user_info
用户信息表,当咱们设置为false
后须要经过实现ApiBootStoreDelegate
接口来进行自定义查询的用户信息。segmentfault
api-boot-starter-security-oauth-jwt
这个依赖内部也默认集成了OAuth2
,并且默认的数据存储方式与Spring Security
一致也是内存方式(memory
),咱们本章的主要目的是查询认证用户信息
,而不是客户端信息
,因此咱们仍是采用默认的内存方式,不过修改下客户端的默认配置信息,在application.yml
文件内添加配置以下所示:
# ApiBoot配置 api: boot: oauth: # ApiBoot OAuth2的客户端列表 clients: - clientId: hengboy clientSecret: chapter grantTypes: password,refresh_token
在ApiBoot
中OAuth2
默认的客户端配置信息,能够经过查看org.minbox.framework.api.boot.autoconfigure.oauth.ApiBootOauthProperties.Client
源码了解详情。
配置已经完成,下面咱们来编写查询用户信息,将用户信息交给ApiBoot Security
框架进行认证
、生成AccessToken
等操做。
本章使用的持久化框架是ApiBoot MyBatis Enhance
,具体的使用方法请查看官方文档。
咱们在数据库内建立一张名为system_user
的系统用户信息表,表结构以下所示:
CREATE TABLE `system_user` ( `su_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户编号', `su_login_name` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '登陆名', `su_nick_name` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '昵称', `su_password` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户密码', `su_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立时间', `su_status` int(11) DEFAULT '1' COMMENT '用户状态,1:正常,0:冻结,-1:已删除', PRIMARY KEY (`su_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统用户信息表';
system_user
用户表建立完成后,咱们往这张表内添加一条用户数据,以下所示:
INSERT INTO `system_user` VALUES ('9b69fd26-14db-11ea-b743-dcd28627348e','yuqiyu','恒宇少年 - 于起宇','$2a$10$RbJGpi.v3PwkjrYENzOzTuMxazuanX3Qa2hwI/f55cYsZhFT/nX3.','2019-12-02 08:13:22',1);
咱们在登陆时用户名对应su_login_name
字段,而密码则是对应su_password
字段,yuqiyu
这个用户的密码初始化为123456
,密码的格式必须为BCryptPasswordEncoder
加密后的密文。
针对system_user
表咱们须要来建立一个ApiBoot MyBatis Enhance
使用的实体,建立一个名为SystemUser
的实体以下所示:
/** * 系统用户基本信息 * * @author 恒宇少年 */ @Data @Table(name = "system_user") public class SystemUser implements UserDetails { /** * 用户编号 */ @Id(generatorType = KeyGeneratorTypeEnum.UUID) @Column(name = "su_id") private String userId; /** * 登陆名 */ @Column(name = "su_login_name") private String loginName; /** * 昵称 */ @Column(name = "su_nick_name") private String nickName; /** * 密码 */ @Column(name = "su_password") private String password; /** * 建立时间 */ @Column(name = "su_create_time") private String createTime; /** * 用户状态 * 1:正常,0:已冻结,-1:已删除 */ @Column(name = "su_status") private Integer status; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Collections.EMPTY_LIST; } @Override public String getUsername() { return this.loginName; } @Override public String getPassword() { return this.password; } /** * UserDetails提供的方法,用户是否未过时 * 可根据本身用户数据表内的字段进行扩展,这里为了演示配置为true * * @return */ @Override public boolean isAccountNonExpired() { return true; } /** * UserDetails提供的方法,用户是否未锁定 * 可根据本身用户数据表内的字段进行扩展,这里为了演示配置为true * * @return */ @Override public boolean isAccountNonLocked() { return true; } /** * UserDetails提供的方法,凭证是否未过时 * 可根据本身用户数据表内的字段进行扩展,这里为了演示配置为true * * @return */ @Override public boolean isCredentialsNonExpired() { return true; } /** * UserDetails提供的方法,是否启用 * * @return */ @Override public boolean isEnabled() { return this.status == 1; } }
具体的注解使用详见ApiBoot MyBatis Enhance
文档,这里还一点须要注意的是,SystemUser
实现了UserDetails
接口,若是使用过Spring Security
的同窗应该都知道这是Spring Security
提供的用户详情接口定义,咱们若是自定义查询用户
就应该让咱们自定义的用户实体
(注:这是的自定义用户实体也就是SystemUser实体)实现这个接口并所有实现UserDetails
接口内提供的方法。
用户的实体已经建立完成,咱们本章须要一个根据用户的登陆名
来查询用户基本的数据接口,建立一个名为SystemUserEnhanceMapper
的接口以下所示:
/** * ApiBoot Enhance提供的加强Mapper * 自动被扫描而且注册到IOC * * @author 恒宇少年 * @see org.minbox.framework.api.boot.autoconfigure.enhance.ApiBootMyBatisEnhanceAutoConfiguration */ public interface SystemUserEnhanceMapper extends EnhanceMapper<SystemUser, Integer> { /** * 根据用户登陆名查询用户信息 * * @param loginName {@link SystemUser#getLoginName()} * @return {@link SystemUser} */ SystemUser findByLoginName(@Param("loginName") String loginName); }
该接口继承了EnhanceMapper<Entity,ID>
接口,能够自动被扫描到建立代理的实例
后而且加入IOC
,这样咱们在项目其余的地方能够直接注入使用。
注意:findByXxx
方法是ApiBoot MyBatis Enhance
提供的方法命名规则查询,多个查询条件可使用And
或者Or
追加,会自动根据方法的规则生成对应的SQL
。
ApiBoot Security
提供了一个接口ApiBootStoreDelegate
,这个接口主要是用来查询登陆用户的具体信息的做用,当咱们经过grant_type=password&username=xxx
的方式进行获取AccessToken
时,ApiBoot Security
会直接把username
的参数值传递给ApiBootStoreDelegate#loadUserByUsername
的方法内,这样咱们就能够根据username
进行查询用户并返回给ApiBoot Security
作后续的认证操做。
咱们来建立一个名为UserService
的类并实现ApiBootStoreDelegate
接口,以下所示:
/** * 自定义读取用户信息 * * @author 恒宇少年 */ @Service public class UserService implements ApiBootStoreDelegate { /** * logger instance */ static Logger logger = LoggerFactory.getLogger(UserService.class); /** * 用户数据接口 */ @Autowired private SystemUserEnhanceMapper mapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDetails userDetails = mapper.findByLoginName(username); if (ObjectUtils.isEmpty(userDetails)) { throw new UsernameNotFoundException("用户:" + username + ",不存在."); } logger.info("登陆用户的信息:{}", JSON.toJSONString(userDetails)); return userDetails; } }
loadUserByUsername
方法的返回值是UserDetails
接口类型,在以前咱们已经将SystemUser
实现了该接口,因此咱们能够直接将SystemUser
实例做为返回值。
代码一切就绪,经过XxxxApplication
的方式来启动项目。
在获取AccessToken
以前,咱们须要确认application.yml
文件内配置的api.boot.oauth.clients
的客户端的clientId
、clientSecret
配置内容,下面是经过CURL
的方式:
➜ ~ curl hengboy:chapter@localhost:9090/oauth/token -d 'grant_type=password&username=yuqiyu&password=123456' {"access_token":"3beb1bee-9ca6-45e1-9fb8-5fc181670f63","token_type":"bearer","refresh_token":"d2243e18-8ab3-4842-a98f-ebd79da94e2e","expires_in":7199,"scope":"api"}
复制上面获取到的refresh_token
的值进行刷新,下面是刷新AccessToken
的CURL
方式:
➜ ~ curl hengboy:chapter@localhost:9090/oauth/token -d 'grant_type=refresh_token&refresh_token=d2243e18-8ab3-4842-a98f-ebd79da94e2e' {"access_token":"e842c2ee-5672-49db-a530-329186f36492","token_type":"bearer","refresh_token":"d2243e18-8ab3-4842-a98f-ebd79da94e2e","expires_in":7199,"scope":"api"}
hengboy
这个OAuth2
客户端在application.yml
中经过配置grantTypes
受权了两种grant_type
,分别是password
、refresh_token
,若是须要别的方式能够在配置文件内对应添加。
ApiBoot
整合Spring Security
以及OAuth2
后读取自定义用户信息,咱们只须要关注具体怎么读取用户信息,以前那些懵懵懂懂的代码配置均可以经过配置文件
的方式代替,本章的主要内容是ApiBootStoreDelegate
这个接口,ApiBoot
所提供的功能还不止这些,会陆续分享给你们。
微信扫描下图二维码关注“程序员恒宇少年”后,回复“源码”便可获取源码仓库地址。
本章节源码在spring-boot-chapter
仓库内目录为SpringBoot2.x/apiboot-security-oauth-custom-certification-user
做者我的 博客
使用开源框架 ApiBoot 助你成为Api接口服务架构师