初识Spring Security OAuth2

这篇博客详细介绍了如何使用Spring Security OAuth2构建认证服务器和资源服务器,包括授权码模式的实现、项目准备、登录授权过程、Token的生成与验证,以及用户名密码、短信和社交登录的重构。文章深入解析了核心源码,帮助读者理解OAuth2的登录流程和Spring Security OAuth2的工作原理。
摘要由CSDN通过智能技术生成

SpringSecurityOAuth来开发认证服务器和资源服务器

SpringSecurityOAuth其实已经帮我们默认实现了以下一些东西:

  • 认证服务器

    • oauth2的认证方式有四种授权模式:授权码简单账户密码客户端,具体请自行百度不做过多的阐述。 本文基于授权码方式实现
    • Token的生成存储
  • 资源服务器

    • OAuthAuthenticationProcessingFilter(拦截用户请求中的token并从认证服务器中寻找对应的用户信息)

如下图所示:
在这里插入图片描述

授权码模式:

在这里插入图片描述

项目准备


1. 添加依赖

		<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-test</artifactId>
         </dependency>

2. 配置认证服务器

@Configuration
 @EnableAuthorizationServer//是的,没做,就这么一个注解
 public class MerryyouAuthorizationServerConfig {
   

 }

有了这个注解表示我们的认证服务器已经默认实现了。启动一下我们会看到如下信息:
在这里插入图片描述
/oauth/authorize表示引导用户跳转去授权的路径,/oauth/token表示通过授权码获取token的路径。按照OAuth2的协议规范,我们去跳转授权的时候需要用这样的路径去访问:http://localhost:8060/oauth/authorize?response_type=code&client_id=imooc&redirect_uri=http://www.jianshu.com&scope=all
这些参数什么意思呢?其实理解他们并不难,这里不建议大家去死记硬背,而是要把自己想象一下授权的时候需要什么东西?
1.首先我们要知道哪一个应用再授权?比如我们要知道是简书需要授权还是慕课需要授权?client_id就是服务提供商给每个应用分配的id,所以请求的时候需要这个参数。这个clientId可以在应用启动的时候看到如下图所示:
在这里插入图片描述
2.第三方应用在请求我的哪一个用户授权?所以我们必须要得到用户名。但是请求参数中没有用户名啊?这不是在忽悠吗~~如下图所示:
在这里插入图片描述
我们访问的/oauth/authorize的弹出框就需要我们填写这个东东
3.给你哪些授权?scope=all表示全部权限拿到。这个参数带的值是由服务提供商定义的,所以不要乱填写~

登录并授权

在这里插入图片描述
我们发现这样我们就获取到了code~~

获取token

这里我们必须要发起post请求
我们要在请求头里面包含我们配置的clientId和clientSecret,然后在按照OAuth协议填写好请求参数:
springsecurity basic 认证
在这里插入图片描述

在这里插入图片描述
得到的access_token如下:
在这里插入图片描述

3. 配置资源服务器

 @Configuration
 @EnableResourceServer//咦,没错还是一个注解
 public class MerryyouResourceServerConfig {
   
 }
  1. 配置application.yml客户端信息(不配置的话,控制台会默认打印clientidclietSecret
 security:
   oauth2:
     client:
       client-id: merryyou
       client-secret: merryyou
  1. 定义MyUserDetailsService
 @Component
 public class MyUserDetailsService implements UserDetailsService {
   

     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
   
         return new User(username, "123456", AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
     }
 }

如果不配置ROLE_USER,即使我们输入了正确的用户名和密码也会403拒绝。

  1. 添加测试类SecurityOauth2Test(用户名密码模式)
 @RunWith(SpringRunner.class)
 @SpringBootTest
 @Slf4j
 public class SecurityOauth2Test {
   
     //端口
     final static long PORT = 9090;
     //clientId
     final static String CLIENT_ID = "merryyou";
     //clientSecret
     final static String CLIENT_SECRET = "merryyou";
     //用户名
     final static String USERNAME = "admin";
     //密码
     final static String PASSWORD = "123456";
     //获取accessToken得URI
     final static String TOKEN_REQUEST_URI = "http://localhost:"+PORT+"/oauth/token?grant_type=password&username=" + USERNAME + "&password=" + PASSWORD+"&scope=all";
     //获取用户信息得URL
     final static String USER_INFO_URI = "http://localhost:"+PORT+"/user";

     @Test
     public void getUserInfo() throws Exception{
   
         RestTemplate rest = new RestTemplate();
         HttpHeaders headers = new HttpHeaders();
         headers.add( "authorization", "Bearer " + getAccessToken() );
         HttpEntity<String> entity = new HttpEntity<String>(null, headers);
         // pay attention, if using get with headers, should use exchange instead of getForEntity / getForObject
         ResponseEntity<String> result = rest.exchange( USER_INFO_URI, HttpMethod.GET, entity, String.class, new Object[]{
    null } );
         log.info("用户信息返回的结果={}",JsonUtil.toJson(result));
     }

     /**
      * 获取accessToken
      * @return
      */
     private String getAccessToken(){
   
         RestTemplate rest = new RestTemplate();
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType( MediaType.TEXT_PLAIN );
         headers.add("authorization", getBasicAuthHeader());
         HttpEntity<String> entity = new HttpEntity<String>(null, headers);
         ResponseEntity<OAuth2AccessToken> resp = rest.postForEntity( TOKEN_REQUEST_URI, entity, OAuth2AccessToken.class);
         if( !resp.getStatusCode().equals( HttpStatus.OK )){
   
             throw new RuntimeException( resp.toString() );
         }
         OAuth2AccessToken t = resp.getBody();
         log.info("accessToken={}",JsonUtil.toJson(t));
         log.info("the response, access_token: " + t.getValue() +"; token_type: " + t.getTokenType() +"; "
                 + "refresh_token: " + t.getRefreshToken() +"; expiration: " + t.getExpiresIn() +", expired when:" + t.getExpiration() );
         return t.getValue();

     }

     /**
      * 构建header
      * @return
      */
     private String getBasicAuthHeader(){
   
         String auth = CLIENT_ID + ":" + CLIENT_SECRET;
         byte[] encodedAuth = Base64.encodeBase64(auth.getBytes());
         String authHeader = "Basic " + new String(encodedAuth);
         return authHeader;
     }
 }






带着token去访问资源

在这里插入图片描述
这里我们一个简单的默认模式就跑完了,但是还是有很多优化的地方~

授权码模式效果如下:
在这里插入图片描述
测试类打印accessToken信息

2018-01-20 18:16:49.900  INFO 16136 --- [           main] cn.merryyou.security.SecurityOauth2Test  : accessToken={
   
  "value": "8e5ea72c-d153-48f5-8ee7-9b5616fc43dc"
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值