Oauth2有以下授权模式:

  1. 授权码模式(Authorization Code)
  2. 隐式授权模式(Implicit)
  3. 密码模式(Resource Owner Password Credentials)
  4. 客户端模式(Client Credentials)

其中授权码模式和密码模式应用较多

授权码模式

授权码授权流程:

  1. 客户端请求第三方授权
  2. 认证服务器生成用户授权协议,用户同意授权,认证服务器将协议唯一号(授权码)响应给客户端
  3. 客户端获得授权码, 然后请求认证服务器申请令牌
  4. 认证服务器生成令牌后向客户端响应令牌
  5. 客户端请求资源服务器的资源,资源服务器校验令牌合法性,完成授权
  6. 资源服务器返回受保护资源

oauth2设置refreshToken过期时间_jwt

请求认证服务获取授权码

固定表名:oauth_client_details(此表名不可修改)

Get请求:
http://localhost:9200/oauth/authorize?
client_id=changgou&response_type=code&scop=app&redirect_uri=http://localhost



client_id:客户端id,和授权配置类中设置的客户端id一致。
response_type:授权码模式固定为code
scop:客户端范围,和授权配置类中设置的scop一致。
redirect_uri:跳转uri,当授权码申请成功后会跳转到此地址,并在后边带上code参数(授权码)

oauth2设置refreshToken过期时间_客户端_02

获取令牌【授权码模式】

Post请求:
http://localhost:9200/oauth/token

【header】
clinet_id:客户端名
client_secret:客户端密码

【body】
grant_type:授权类型,填写authorization_code,表示授权码模式
code:授权码,就是刚刚获取的授权码,注意:授权码只使用一次就无效了,需要重新申请。
redirect_uri:申请授权码时的跳转url,一定和申请授权码时用的redirect_uri一致。

【Authorization】
TYPE:Basic Auth
username:账号
password:密码





{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJhcHAiXSwibmFtZSI6bnVsbCwiaWQiOm51bGwsImV4cCI6MTYwMDYzMDU2MiwianRpIjoiMTBlNThkYWMtMzRmZC00OWQxLThlZjctZGUzYzZlZjU3Mzg5IiwiY2xpZW50X2lkIjoiY2hhbmdnb3UiLCJ1c2VybmFtZSI6ImNoYW5nZ291In0.JrDYPSqooM57epYYdiipMf6tC9i6MZolySHf4an4BbTcZIvqLy39UIsXPK27bL8LGtaaZYFKW0FKHuNlUrX5hg8qCZhOuzOJGAJfGAFf1DiVCOVph-pE4P0va3MXkUYmLSXxgcJBSTuG31L3nnatvPU0__WfbjnJjAD_DWb20wOtET4E8Iv2L1kcmtSSswYnlY6actlqfdns93JHmZewPh8i647H0rvBzIlO0N6ZMkmfWxRL9dMv80dwSMCmsvHD0W0I8w4c8Ns18iwzYFPjqtEajlcW6DmERI1sd94aUl96cBD0uijpgpec226KclZ8h-_oRzGb3pSAqiaJQX711w",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJhcHAiXSwiYXRpIjoiMTBlNThkYWMtMzRmZC00OWQxLThlZjctZGUzYzZlZjU3Mzg5IiwibmFtZSI6bnVsbCwiaWQiOm51bGwsImV4cCI6MTYwMDYzMDU2MiwianRpIjoiMDAzN2Q4MzUtYzQ0OC00NjI5LWI2MTYtMmNmNDVkNDQxYzc3IiwiY2xpZW50X2lkIjoiY2hhbmdnb3UiLCJ1c2VybmFtZSI6ImNoYW5nZ291In0.hbksRM6PkOPEcBs7VS5W8-EUNSraKo5TWgjJk53tZC6rOxyTGd9HOf7dM6CDZ9GuEKoSWVSARMcyYU6RyGJrkURc4VBBXjGydrO3Zn7esoR291CVS8gLLjoMhYwq_rchgrsx9P6MOIT0PapsQr321I7d6EwYR7zKU8cuMA0L1HqewpZxjP1BtVtMln52CUADqzYa8uuPb4FkORbfzVR-mjBZrkM96lXxa5z2asMEBsve9CGxhXGvaWW5Iw_DNNpjbYvT5v2qJ5z7BzaUydmzhoX_GIcyo2UedycoevBgSItIEE-C7vSUvHswuL_aUsRBxCsdBe2AqJZE-r4mQ5EZoQ",
    "expires_in": 43199,
    "scope": "app",
    "jti": "10e58dac-34fd-49d1-8ef7-de3c6ef57389"

校验令牌

Get请求:
http://localhost:9200/oauth/check_token?token=[access_token]



结果:
{
    "scope": [
        "app"
    ],
    "name": null,
    "active": true,
    "id": null,
    "exp": 1600630562,
    "jti": "10e58dac-34fd-49d1-8ef7-de3c6ef57389",
    "client_id": "changgou",
    "username": "changgou"
}

刷新令牌(令牌和时间都会更新)

Post:http://localhost:9200/oauth/token
参数:
grant_type: 固定为 refresh_token
refresh_token:刷新令牌(注意不是access_token,而是refresh_token)



结果:
{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJhcHAiXSwiZXhwIjoxNjAwNjMyMTkxLCJqdGkiOiJkMGMwMzRkZS00YjY5LTQ1YTYtODIyZi00NTkxMDg0OWVjMWUiLCJjbGllbnRfaWQiOiJjaGFuZ2dvdSJ9.iLcwZUHjeFHKWwt_54CpxEEiPpzPqjHJSNeq5RYctGNygmFu-HxhOgRy83h2st-GucfIPGyEPiDt2JtndwhWVpdLY0JrrF2n2zeFLEtuc1Y7IzoJrsBKyHSN6sDErkdwnxuKAVGXIFp8miQy1qXsR7SN-LQ5i1j8S56vfyFvxitIiTqCkj4lcDUU0aki9EpsKDBt9K-RQ9sddqcpV9L3Y2wT0PeBeXRbVj25fCc7WOrSod0qQHDcIz3PHs4RiHfRENg2lm-ZwpuTHIBQolKqn3_oLUcUTAS9LkzodtZ_0eqPOvp1izfT3e46laRZxFQ-AcNNvSGm8rvwbQoQaICTTw",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJhcHAiXSwiYXRpIjoiZDBjMDM0ZGUtNGI2OS00NWE2LTgyMmYtNDU5MTA4NDllYzFlIiwiZXhwIjoxNjAwNjMwNTYyLCJqdGkiOiIwMDM3ZDgzNS1jNDQ4LTQ2MjktYjYxNi0yY2Y0NWQ0NDFjNzciLCJjbGllbnRfaWQiOiJjaGFuZ2dvdSJ9.WBLLpmQ4ScekpQ7SjMrLqEtvUr2NXO1H-WVs13GK1LqBcUUrP-Qbz144itjraT6Bckw2gebojbbljQ-nze3ubS--d9zQkQL6y3cqUn7KNfTPmxIK-BXQ3QD5Rb7SMP4fX4IgeGE77uELHOXN9zCu4_Er7wX7-IhkllwBicOWP7FiXi5UIVDpf380NnWBwXlxugGI5DhW40ON50wdTnkvjmMZozRYgOO8LqejB6MKj4zX9hMoRs3eM6y2eXKj3spWiRr4e0oRZwx9m9X-0DB499hCWd6CQtxgIq4c5b6dZjNAw9XXrego9xQqcdRbKSLhbvK5fVXbt9KhEV6tqVic9A",
    "expires_in": 43199,
    "scope": "app",
    "jti": "d0c034de-4b69-45a6-822f-45910849ec1e"
}

获取令牌【密码模式】

密码模式与授权码模式的区别是申请令牌不再使用授权码,而是直接通过用户名和密码即可申请令牌,一般用于内部系统之间,进行授权访问。

申请令牌:

Post请求:
http://localhost:9200/oauth/token

【header】
clinet_id:客户端名
client_secret:客户端密码

【body】
携带参数:
grant_type:密码模式授权填写password
username:账号
password:密码

结果:
{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJhcHAiXSwibmFtZSI6bnVsbCwiaWQiOm51bGwsImV4cCI6MTYwMDYzMjk1MCwiYXV0aG9yaXRpZXMiOlsic2Vja2lsbF9saXN0IiwiZ29vZHNfbGlzdCJdLCJqdGkiOiIzZTEzOGMzNS0xZjUzLTQ0YzMtYTMyMC04MTc1MWI2ZDllYTYiLCJjbGllbnRfaWQiOiJjaGFuZ2dvdSIsInVzZXJuYW1lIjoiaXRoZWltYSJ9.utWFXzdHT2DhiHEozbqv61MubL96rWg_V4evU1dG4Pq-33nYXZ1wTi5XBvYiLDzwCroVr69B5nwx21VoiG3cz2QCyVyeyS2k3iRX8mXMWJcaa_1ojjKyLLHpqWJ0Xerr1OIOaN-RLJm2Wlu4InSyTUgxCOdDXYD43g2o37nL51b3wBkQrRtLs_qMwIuj6a4oM2gW53iY0mN84Hw4AAD2UBFPJ6Mhix-Ip1DsSqavDPG3Do2WJrfu78q_O6b_UP9SaO7fuURj6szoSbqmqKudze-AWy15Gpeemz2WIt0_0jB4nO5U7Xr6aGjRseN9wivhaIfbz4vHquUJog7z0zdE0g",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJhcHAiXSwiYXRpIjoiM2UxMzhjMzUtMWY1My00NGMzLWEzMjAtODE3NTFiNmQ5ZWE2IiwibmFtZSI6bnVsbCwiaWQiOm51bGwsImV4cCI6MTYwMDYzMjk1MCwiYXV0aG9yaXRpZXMiOlsic2Vja2lsbF9saXN0IiwiZ29vZHNfbGlzdCJdLCJqdGkiOiJkNmFjOGNiYS1hNmM1LTRhOTQtOWMzYy0yMzFmMmY4MjgyNTEiLCJjbGllbnRfaWQiOiJjaGFuZ2dvdSIsInVzZXJuYW1lIjoiaXRoZWltYSJ9.R5jNy3-z1vg1a2gJBionUwUVDMC6Ig6hagUePIiIvovBayO72UTJX46LOBi0T6ORbF3Z5n3CFRH4cBw6LtOv1h7y2VZyYMKFtJEPzrfZe-KmqIMo0n9B1Mc9qoEH-AOOKzFSOcrtzU6qTgsgc_YrrthC-5srsg8UB4XDkahRDIytCu48zn0PNXL8I961kMNaI-s426Fo2nm_-yWDqktbQi1nrtFg37QrvO4oBBHYHj0Zf0sSshqGV25uKjAelGpzO95-7paW9cOBK2ue3GBP-RKFfUnSvCX_HZj6pZX8DnoIAEb1EbT0tuWT8zYmwKWpXzNAW12rQj7pMPIYjq6NGw",
    "expires_in": 43199,
    "scope": "app",
    "jti": "3e138c35-1f53-44c3-a320-81751b6d9ea6"
}

资源服务授权(服务对接)

资源服务拥有要访问的受保护资源,客户携带令牌访问资源服务,如果令牌合法则可以成功访问资源服务中的服务。

流程图:

oauth2设置refreshToken过期时间_ci_03

  1. 客户端请求认证服务申请令牌
  2. 认证服务生成令牌认证服务采用非对称加密算法,使用私钥生成令牌。
  3. 客户端携带令牌访问资源服务客户端在Http header中添加:Authorization: Bearer令牌。
  4. 资源服务请求认证服务校验令牌的有效性资源服务接收到令牌,使用公钥校验令牌的合法性。
  5. 令牌有效,资源服务向客户端响应资源信息

步骤:

  1. 导入依赖
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
  1. 配置每个系统的Http请求路径安全控制策略以及读取公钥信息识别令牌,如下:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的PreAuthorize注解
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    //公钥
    private static final String PUBLIC_KEY = "public.key";

    /***
     * 定义JwtTokenStore
     * @param jwtAccessTokenConverter
     * @return
     */
    @Bean
    public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
        return new JwtTokenStore(jwtAccessTokenConverter);
    }

    /***
     * 定义JJwtAccessTokenConverter
     * @return
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setVerifierKey(getPubKey());
        return converter;
    }
    /**
     * 获取非对称加密公钥 Key
     * @return 公钥 Key
     */
    private String getPubKey() {
        Resource resource = new ClassPathResource(PUBLIC_KEY);
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
            BufferedReader br = new BufferedReader(inputStreamReader);
            return br.lines().collect(Collectors.joining("\n"));
        } catch (IOException ioe) {
            return null;
        }
    }

    /***
     * Http安全配置,对每个到达系统的http请求链接进行校验
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        //所有请求必须认证通过
        http.authorizeRequests()
                //下边的路径放行
                .antMatchers(
                        "/user/add","/user/load/**"). //配置地址放行
                permitAll()
                .anyRequest().
                authenticated();    //其他地址需要认证授权
    }
}
  1. 测试
    不带令牌测试:localhost:9005/user
    返回错误信息:
{
 "error": "unauthorized",
 "error_description": "Full authentication is required to access this
resource"
}

带令牌测试,返回正确信息:

{
    "flag": true,
    "code": 20000,
    "message": "查询成功",
    "data": [
    {
    	...
    }