Spring-Cloud's OAuth2 of JWT protection -12

  A, the JWT: JSON Web Token (the JWT) is an open standard (RFC 7519), JWT defines a compact and self-contained in the standard, which aims to package information for each body of a JSON object. Subject information through digital signature and verification. Often used HMAC algorithm or the RSA (public / private asymmetric cipher> JWT signing algorithm, the security is high.

  1) Features:

  (1) compact (compact): Since the character string is encrypted, the JWT data volume is very small, the request may be sent by the first parameter POST request or HTTP. Further, small size means that data transmission quickly.

  (2) self-contained (self-contained): JWT contains all the information the subject, so avoiding the need Uaa service each request to verify identity, reducing the load on the server.

  2) structure: comprising three parts, by "(dot)." Segmentation .

  (1) Header (header).

  (2) Payload (payload>.

  (3) Signature (signature).

  Probably look like the following:

  

  Parsed like this:

  

  Two, JWT scenarios.

  1) Certification: This is the most common JWT scene. Once the user logs in successfully obtaining JWT, each subsequent request carries the JWT. The JWT contains user information, permissions, points, etc., according to the information contained in the JWT, resource services to control the resources of the JWT can access. JWT because overhead is small, and can be used in a different domain, single sign-on is a widely used JWT scene.

  2) Information exchange: JWT is a way to secure transmission of information between the parties, using the signature encryption, security is very high. In addition, when using the Header Payload operator signature can also verify that the content has been tampered with.

  Three, JWT how to use.

  The client by providing a user name, a password request to the server to obtain JWT, after the server determines the user name and password are correct, the user information and permission to return to JWT point encrypted form to the client. Get to the JWT clients need to bring the benefits of doing so is to JWT future requests do not require the user to judge the request and the user's permission through certification services in each subsequent request. In the micro-service system, you can take advantage of single sign-JWT.

  

 

  Fourth, the specific implementation process. (Basic and (in the previous chapter OAuth2 open Spring-Cloud of -11 authorization code), I just say here that the core of the modified section)

  1, the authentication server amend section

package com.cetc.config;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;

@Configuration
@EnableAuthorizationServer
public class AuthServerConfiguration extends AuthorizationServerConfigurerAdapter{

    @Autowired
    private AuthDetailsService authDetailsService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Bean
    public ClientDetailsService clientDetailsService(HikariDataSource dataSource) {
        //使用数据库的配置方式
        return new JdbcClientDetailsService(dataSource);
    }

    @Bean
    public TokenStore tokenStore() {
        //token也使用数据的方式,后面会将JWT的使用方式
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    protected JwtAccessTokenConverter jwtAccessTokenConverter() {
        ClassPathResource resource = new ClassPathResource("jwt/jwt.jks");
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, "auth_jwt".toCharArray());
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair("oauth2-jwt"));
        return jwtAccessTokenConverter;
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                //token获取方式
                .tokenKeyAccess("permitAll()")
                //检测加入权限
                .checkTokenAccess("isAuthenticated()")
                //允许表单认证
                .allowFormAuthenticationForClients();

    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //这里就是具体的授权管理过程了
        clients.withClientDetails(clientDetailsService);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                //这里使用的认证方式为security配置方式
                .authenticationManager(authenticationManager)
                //提供get和post的认证方式
                .allowedTokenEndpointRequestMethods(HttpMethod.POST, HttpMethod.GET)
                //这里一定要配置userDetailsService,不然刷新token会出错,refresh_token
                .userDetailsService(authDetailsService)
                .tokenStore(tokenStore()).tokenEnhancer(jwtAccessTokenConverter())
                //自定义认证页面
                .pathMapping("/oauth/confirm_access", "/oauth/confirm_access");
    }

}

  2、资源服务器

  

package com.cetc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
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.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.util.FileCopyUtils;

import java.io.IOException;
import java.util.Arrays;

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .anyRequest().authenticated();
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() throws IOException {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        ClassPathResource resource = new ClassPathResource("jwt/jwt.cert");
        jwtAccessTokenConverter.setVerifierKey(new String(FileCopyUtils.copyToByteArray(resource.getInputStream())));
        return jwtAccessTokenConverter;
    }

    @Bean
    public TokenStore tokenStore() throws IOException {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(tokenStore());
    }
}

  3、第三方或者SSO客户端,不做修改。因为,JWT令牌是认证服务器给出的。解析JWT令牌的为资源服务器,所以SSO客户端只需要按原来的方式进行调用就可以了。

  五、jks文件生成,上面使用jks文件为文件token密钥,所以我们在使用的时候需要自己加入。

  1)生成jks文件 

keytool -genkeypair -alias oauth2-jwt -keyalg RSA -keypass auth_jwt -storepass auth_jwt -keystore jwt.jks

  2)获取公钥,这里最好在linux服务器上面进行,本地安装OpenSSL过于麻烦

keytool -list -rfc --keystore jwt.jks | openssl x509 -inform pem -pubkey

  

 

 

   赋值公钥到jwt.cert文件中

  

  3)按照配置的指定路径放入jwt.jks和jwt.cert

  六、测试资源服务器访问,启动Eureka-Server、Eureka-Client、Auth-Server-Jwt、Auth-Resource-Jwt端口为8670、8673、8697、8698.

  

 

 

   1)添加客户端到数据库

  

 

 

   2)获取令牌:

  (1)获取授权码

oauth/authorize?response_type=code&client_id=&redirect_uri=

  

  (2)获取令牌

oauth/token?client_id=&client_secret=&grant_type=authorization_code&redirect_uri=&code=

  

   

 

 

   3)携带令牌访问资源服务器

  

  七、JWT的基本使用就差不多这个样子了,JWT的目的是在较少认证服务器的访问。那么这个也存在问题就是如果用户权限修改或者其他部分修改,那么在令牌的使用就不是最新的,这里就会导致权限错误问题。当然这个问题可以通过配置网关,在网关处缓存,如果存在修改这清楚缓存,要求重新登录。

  八、本编源码:https://github.com/lilin409546297/spring-cloud/tree/master/oauth2-jwt

Guess you like

Origin www.cnblogs.com/ll409546297/p/12187608.html