当前应用需要实现第三方登入,那么第三方是如何进行授权认证的?这就是oauth2协议。
模拟实现微信端是如何进行授权认证登入。
举例:豆瓣就是客户应用,授权服务器、资源服务器就是微信端持有。豆瓣需要向微信的授权服务器获取授权,获取到授权后再向资源服务器获取用户信息。
那么我们就需要
1.需要配置一个授权服务器(发放授权码)
2.配置一个资源服务器(获取用户信息接口需要令牌才能访问)
3.配置一个接口(获取返回用户信息)
4.还要实现模拟用户的登入(因为授权服务器需要向用户发起是否允许授权的请求)
在spring-security-oauth2中有这几个默认接口,按照以下接口访问顺序获取用户信息:
/oauth/authorize:获取授权码 /oauth/token:根据授权码获取令牌 /user/getUser:根据令牌获取user资源信息
整个项目结构
项目依赖的pom文件:
注意:spring-cloud和spring-boot的版本一定要兼容适配,否则会报错
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</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>
<dependencyManagement>
<dependencies>
<!--springCloud的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
授权服务器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
/**
* 授权服务器配置,客服端向此请求获取授权码
*
* 访问以下地址获取授权码:以下地址就是获取授权码的配置
* http://localhost:8080/oauth/authorize?client_id=admin&response_type=code
*
* /oauth/authorize:获取授权码接口
* response type=code:响应类型为授权码
* client_d=admin:访问的授权服务器id
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("admin") // 配置client-id
.secret(passwordEncoder.encode("12334")) // 授权服务器的密码
.accessTokenValiditySeconds(3600) // 时间有效期
.redirectUris("http://www.baidu.com") // 授权成功后跳转地址(并且会带上授权码code)
.scopes("all") // 授权范围
.authorizedGrantTypes("authorization_code"); // 授权码模式
}
}
资源服务器
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
/**
* 资源服务管理,配置某些接口需要携带令牌才能访问获取资源
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.requestMatchers()
.antMatchers("/user/**");// 需要携带令牌才能访问获取资源
}
}
获取用户信息接口
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/getUser")
public Object getUser(){
return "成功获取到资源";// 给第三方网站返回用户信息(三方登入)
}
}
配置用户登入信息
@Service
public class UserService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 模拟根据username进行DB查询结果设置用户
String password = passwordEncoder.encode("123");
// 设置用户的账号、密码(security根据表单提交的登入信息进行比对)
return new User("admin",password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
配置不需要登入认证才可访问的接口(如登入、退出登入接口)
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login/**","/logout/**")
.permitAll() // 以上接口允许不用授权服务
.anyRequest()
.authenticated() // 其它接口需要授权
.and()
.formLogin()
.permitAll();
}
}
配置好以上信息后就可以开始进行测试了
第一步:访问http://localhost:8080/oauth/authorize?client_id=admin&response_type=code获取授权码code,首次获取时我们需要先登入用户(就好比如果手机微信不登入怎么进行授权)
登入成功后就会跳到这个页面(这个就是授权页面,就和微信询问你是否允许第三方应用登入一样)
选择允许授权后,跳到百度页面,并且携带了授权码code
接下来,我们就可以使用接口测试工具去获取令牌了(我使用的是Apifox)记得请求的端口要正确,下面截图中忘了写端口了。
发送请求后的返回体,access_token就是返回的令牌
接着携带令牌发送请求获取用户信息
请求结果