OAuth2简化模式

版本:springboot2.2.6.RELEASE
参考文章:OAuth2 授权码模式

做如下修改:

1、auth-server(授权服务器)
修改configure(ClientDetailsServiceConfigurer) 方法部分:只需要在 authorizedGrantTypes 中增加 implicit 表示支持简化模式即可。

AuthorizationServer:

package cn.linst.authserver.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

import java.lang.ref.SoftReference;


/**
 * 简化模式。
 *
 * 在这个auth-server demo中,就是相当于第三方平台。
 * 授权服务器。模拟第三方平台。授权服务器一方面是校验客户端,另一方面则是校验用户。
 * 用户信息校验在SecurityConfig配置了。
 */
@EnableAuthorizationServer  // 表示开启授权服务器的自动化配置
@Configuration
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    TokenStore tokenStore;

    /**
     * 保存的客户端信息
     */
    @Autowired
    ClientDetailsService clientDetailsService;

    /**
     *  令牌相关配置。用来配置 Token 的一些基本信息。
     *  如 Token 是否支持刷新、Token 的存储位置、Token 的有效期以及刷新 Token 的有效期等。
     *  当 Token 快要过期的时候,需要获取一个新的token,获取新的 Token 时候,需要有一个凭证信息,refresh_token。这个 refresh_token 也是有有效期的
     */
    @Bean
    AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(clientDetailsService);
        services.setSupportRefreshToken(true);
        services.setTokenStore(tokenStore);
        // access_token 有效期
        services.setAccessTokenValiditySeconds(60 * 60 * 2);
        // refresh_token 有效期
        services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 3);
        return services;
    }

    /**
     *  AuthorizationServerSecurityConfigurer用来配置令牌端点的安全约束,就是这个端点谁能访问,谁不能访问。
     * checkTokenAccess是指一个 Token 校验的端点,这个端点我们设置为可以直接访问。在资源服务器收到 Token 之后,需要去校验 Token 的合法性,就会访问这个端点。
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 1.  /oauth/check_token   资源服务器会自动校验这个接口,检查token对应的信息。
        // 2. 这里配置为了让这个接口都能访问到。
        // 3. 允许表单登录。
        security.checkTokenAccess("permitAll()")
                .allowFormAuthenticationForClients();
    }

//
//    /** 授权码模式
//     * ClientDetailsServiceConfigurer 用来配置客户端的信息。
//     * 校验客户端
//     */
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        clients.inMemory()
//                .withClient("clientIdForMyApplication") //应用在第三方平台注册,平台给应用生成appid。
//                .secret(new BCryptPasswordEncoder().encode("123"))
//                .resourceIds("res1") // 资源id
//                .authorizedGrantTypes("authorization_code","refresh_token")  // authorization_code:授权码模式 ;refresh_token:刷新token
//                .scopes("all")
                .autoApprove(true)
//                .redirectUris("http://localhost:8082/index.html"); // 授权完成后,重定向的地址。
//    }


    /**
     * 简化模式
     * ClientDetailsServiceConfigurer 用来配置客户端的信息。
     * 校验客户端
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("clientIdForMyApplication") //应用在第三方平台注册,平台给应用生成appid。
                .secret(new BCryptPasswordEncoder().encode("123"))
                .resourceIds("res1") // 资源id
                .authorizedGrantTypes("refresh_token","implicit")  // authorization_code:授权码模式 ;implicit:支持简化模式
                .scopes("all")
//                .autoApprove(true)
                .redirectUris("http://localhost:8082/01.html"); // 授权完成后,重定向的地址。
    }

    /**
     * AuthorizationServerEndpointsConfigurer用来配置令牌的访问端点和令牌服务。
     * authorizationCodeServices用来配置授权码的存储。
     * tokenServices 这个 Bean 主要用来配置 Token 的一些基本信息。
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authorizationCodeServices(authorizationCodeServices())
                .tokenServices(tokenServices());
    }

    /**
     *  授权码保存的地方,存哪都行,一般存内存,授权码用一次就失效了没用了。
     *  授权码与令牌区别:授权码是用来获取令牌的,使用一次就失效,令牌则是用来获取资源。
     *
     */
    @Bean
    AuthorizationCodeServices authorizationCodeServices() {
        return new InMemoryAuthorizationCodeServices();
    }
}

2、因为简化模式没有服务端,我们只能通过 js 来请求资源服务器上的数据,所以资源服务器需要支持跨域,我们修改如下两个地方使之支持跨域。

user-server(资源服务器):
1)在 Controller 上添加 @CrossOrigin 注解使之支持跨域

package cn.linst.userserver;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
// 增加跨越支持
@CrossOrigin(value = "*")
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello。。。";
    }
    @GetMapping("/admin/hello")
    public String admin() {
        return "admin。。。";
    }
}

2)配置 Spring Security 使之支持跨域,在configure(HttpSecurity http)方法增加cors

package cn.linst.userserver.config;

import org.springframework.context.annotation.Bean;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;


/**
 * 模拟第三方平台的资源服务器
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    /**
     * 这是因为资源服务器和授权服务器是分开的,资源服务器和授权服务器是放在一起的。
     * 如果资源服务器和授权服务器是放在一起的,就不需要配置 RemoteTokenServices 了
     *
     */
    @Bean
    RemoteTokenServices tokenServices() {
        // 配置了一个 RemoteTokenServices 的实例。
        // 配置了 access_token 的校验地址、client_id、client_secret 这三个信息。
        // 当用户来资源服务器请求资源时,会携带上一个 access_token,通过这里的配置,就能够
        // 校验出 token 是否正确等。
        RemoteTokenServices services = new RemoteTokenServices();
        services.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
        services.setClientId("clientIdForMyApplication");
        services.setClientSecret("123");
        return services;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("res1").tokenServices(tokenServices());
    }

    /**
     * 配置一下资源的拦截规则,这就是 Spring Security 中的基本写法 。
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")
                .anyRequest().authenticated().and().cors();
    }
}

3、client-app(第三方应用)
在static目录下,新增01.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>hello world 简化模式</title>
    <script src="/jquery-3.5.0.min.js"></script>
</head>
<body>
你好,世界!

<a href="http://localhost:8080/oauth/authorize?client_id=clientIdForMyApplication&response_type=token&scope=all&redirect_uri=http://localhost:8082/01.html">第三方登录(简化模式)</a>

<div id="div1"></div>
<script>
    var hash = window.location.hash;//提取出参数,类似这种格式#access_token=38653449-a3cd-414b-a313-7a1aa9bac0b1&token_type=bearer&expires_in=7069
    if (hash && hash.length > 0) {
        var params = hash.substring(1).split("&");
        var token = params[0].split("=");//[access_token,38653449-a3cd-414b-a313-7a1aa9bac0b1]
        $.ajax({
            type: 'get',
            headers: {
                'Authorization': 'Bearer ' + token[1]
            },
            url: 'http://localhost:8081/hello',
            success: function (data) {
                $("#div1").html(data)
            }
        })
    }
</script>
</body>
</html>

登录成功的页面:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值