SpringOauth2实现Jdbc简单认证登陆
创建一个SpringBoot工程
依赖如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
这里主要依赖的是Spring Security 、Spring Security Oauth2 依赖,创建好项目后我们创建一个User类并且实现UserDetail接口如下:
public class UserInfo implements UserDetails{
private String name;
private String email;
private String password;
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Transient
private List<GrantedAuthority> authorityList;
public List<GrantedAuthority> getAuthorityList() {
return authorityList;
}
public void setAuthorityList(List<GrantedAuthority> authorityList) {
this.authorityList = authorityList;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorityList;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return name;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + '\'' +
", email='" + email + '\'' +
", password='" + password + '\'' +
", authorityList=" + authorityList +
'}';
}
}
这里UserDetail接口我就不多解释了,这几个方法大家都应该很清楚,然后我们创建一个CustomerUserService去实现UserDetailsService接口的loadUserByUsername方法:
@Service
public class CustomerUserService implements UserDetailsService {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo user = new UserInfo();
user.setName(username);
user.setPassword("123456");
log.info("username ->" + username);
if (user.getName().equals("zhoubiao")) {
List<GrantedAuthority> auths = new ArrayList<>();
auths.add(new SimpleGrantedAuthority("ROLE_USER"));
user.setAuthorityList(auths);
log.info("user ->" + user);
return user;
}
return null;
}
}
这里的代码很简单。这里的角色权限都是写死的。不管是用mybatis的mapper还是spring data jpa 都可以通过注入到这里来进行查询操作。这里为了简化操作。我就写死了。
然后我们创建我们的授权服务器:
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends
AuthorizationServerConfigurerAdapter {
@Resource
private DataSource dataSource;
@Bean
public ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.jdbc(dataSource);
}
注意这里的DataSource是依赖Spring Data Jpa 中为我们封装的Spring Jdbc的相关配置依赖。
下面就是我们的资源服务器配置了如下:
@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.requestMatchers()
.antMatchers("/api/**");
}
}
这里注意资源服务器应该是和授权服务器分开的,这里为了演示方便,我把他们放在一起了。这里对/api/
下的所有请求进行拦截认证。
我们在pom.xml中引入了Security 的依赖,那么我们是需要使用到它的,那么我们创建一个WebSecurityConfig并且继承自WebSecurityConfigurerAdapter
这个适配器类
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomerUserService customerUserService;
@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(this.customerUserService);
}
}
这里使用了AuthenticationManagerBuilder
来管理认证信息,最后我们创建一个UserController 来进行测试:
@Controller
public class UserController {
@RequestMapping("/api/userinfo")
public ResponseEntity<UserInfo> getUserInfo() {
UserInfo user = (UserInfo) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
String email = user.getUsername();
user.setName(user.getUsername());
user.setEmail(email);
return ResponseEntity.ok(user);
}
}
下面是application.properties配置:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/_oauth2
spring.datasource.username=root
spring.datasource.password=root
#jpa
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
下面是这个资源需要的sql,这里为什么需要创建sql呢,因为我们是走的jdbc模式,下面这个sql的结构可以从JdbcClientDetailsService
这个类从获取,如下:
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for `oauth_client_details`
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(48) NOT NULL,
`resource_ids` varchar(256) DEFAULT NULL,
`client_secret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`authorized_grant_types` varchar(256) DEFAULT NULL,
`web_server_redirect_uri` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) DEFAULT NULL,
`autoapprove` varchar(256) DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `oauth_client_details`
-- ----------------------------
BEGIN;
INSERT INTO `oauth_client_details` VALUES ('clientapp', null, '112233', 'read_userinfo', 'authorization_code', 'http://localhost:9001/callback', null, '3600', null, null, null);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
然后我们使用chrome浏览器访问http://localhost:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://localhost:9001/callback&response_type=code&scope=read_userinfo
然后出现了身份认证:
我们输入账号和密码点击登陆后:
这里提示我们授权。我们点击Approve,如果点击了Deny就是拒绝授权。
这里我们就拿到了授权码,然后我们使用postman之类的http来进行后面的测试:
这里我们要填入客户端id 和密码,这里是来自数据里面的。这里所有的表单填入的信息都来自数据库表中的数据。
然后我们点击发送:
这里就可以拿到token了。然后我们就可以用token 来换取我们的api服务了
这里就拿到了我们api提供的信息了。
总结
这里使用了授权码模式的oauth2的认证,总体来说很简单的。注意这里的实验是不能用在生产级别的,如果要用到生产级,那么还需要对代码进行多次的封装和配置。