简体   繁体   English

当用户使用jwt,Oauth2和spring security进行首次请求时,如何在服务层上获取jwt令牌字符串?

[英]How to get jwt token string on service layer when user request first time using jwt, Oauth2, spring security?

I am new in development of micro-services with jwt. 我是使用jwt开发微服务的新手。 Here is my project structure: 这是我的项目结构:

First micro-service is used to authenticate users by jwt and Oauth2 using username and password. 第一个微服务用于通过jwt和Oauth2使用用户名和密码对用户进行身份验证。 This microservice is called auth-service. 此微服务称为auth-service。

Login request url is like: 登录请求网址类似于:

[ http://localhost:9092/oauth/token?username=s@sawai.com&password=randomPassword&grant_type=password][1] [ http:// localhost:9092 / oauth / token?username=s@sawai.com&password=randomPassword&grant_type=password] [1]

By calling this url we got jwt token like: 通过调用此URL,我们得到了jwt令牌,例如:

{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyX2lkIl0sInVzZXJfbmFtZSI6InNAc2F3YWkuY29tIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl0sInRlbmFudElkIjoic2F3YWkuY29tIiwic3lzdGVtR2VuZXJhdGVkUGFzc3dvcmQiOnRydWUsImlkIjoiNTYzOTFhYzAtZDc4OC00ODEyLThmYWMtODEwZTIyMjdjYmI1IiwiZXhwIjoxNTI0NzMxNzgwLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6ImY0ZTNmNTM5LWRkNDgtNGMxMy05OTg5LTcwM2E1NWYxMjNlYyIsImVtYWlsIjoic0BzYXdhaS5jb20iLCJjbGllbnRfaWQiOiJ0cnVzdGVkLWFwcCJ9.AS1tXpUcPMgEw63FrvPP-xGBz7qCi14Eqe29rDzTXPg","token_type":"bearer","refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyX2lkIl0sInVzZXJfbmFtZSI6InNAc2F3YWkuY29tIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl0sImF0aSI6ImY0ZTNmNTM5LWRkNDgtNGMxMy05OTg5LTcwM2E1NWYxMjNlYyIsInRlbmFudElkIjoic2F3YWkuY29tIiwic3lzdGVtR2VuZXJhdGVkUGFzc3dvcmQiOnRydWUsImlkIjoiNTYzOTFhYzAtZDc4OC00ODEyLThmYWMtODEwZTIyMjdjYmI1IiwiZXhwIjoxNTI0NzQ2MTgwLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjI1ZmJlY2IyLWRhODgtNDY1ZS1iM2I2LTFlN2NmYjBlYmVjMiIsImVtYWlsIjoic0BzYXdhaS5jb20iLCJjbGllbnRfaWQiOiJ0cnVzdGVkLWFwcCJ9.jSG5zUBzu9yGqnBueU7fkIZV6XhXD8oCkYCerwHkkOw","expires_in":14399,"scope":"read write","tenantId":"sawai.com","systemGeneratedPassword":true,"id":"56391ac0-d788-4812-8fac-810e2227cbb5","email":"s@sawai.com","jti":"f4e3f539-dd48-4c13-9989-703a55f123ec"}

On auth service database we just create a single table called users with following fields: 在身份验证服务数据库上,我们仅创建一个名为users的表,其中包含以下字段:

id varchar(255) id varchar(255)

created_on datetime created_on datetime

last_modified_date datetime last_modified_date日期时间

email varchar(255) 电子邮件varchar(255)

enabled bit(1) 使能位(1)

password varchar(255) 密码varchar(255)

role varchar(255) 角色varchar(255)

system_generated_password bit(1) system_generation_password位(1)

tenant_id varchar(255) tenant_id varchar(255)

validate bit(1) 验证位(1)

OK. 好。

Now another micro-service is called company and in company service we have list of users(not same as auth service users, because auth service contains users for multiple micro-services like: Company, Candidate etc). 现在另一个微服务称为公司 ,在公司服务中我们有用户列表(与auth服务用户不同,因为auth服务包含多个微服务的用户,例如:Company,Candidate等)。

Now we want to maintain last_logged_on for company users. 现在,我们要为公司用户维护last_logged_on So admin can check when an user logged in last time. 因此,管理员可以检查用户上次登录的时间。

What we try to do is: When user login using auth service and user type is company user then call company service and update users last_logged_on . 我们尝试做的是:当使用身份验证服务登录的用户和用户类型为公司用户时,请致电公司服务并更新用户last_logged_on For calling company service we need jwt-access-token because urls are secure on company side. 对于呼叫公司服务,我们需要jwt-access-token,因为网址在公司方面是安全的。 So how can we get access token on auth service when we request to get jwt token. 因此,当我们请求获取jwt令牌时,如何在身份验证服务上获取访问令牌。

Here is configuration for jwt with spring boot on auth side. 这是jwt的配置,其中auth端带有spring boot。

package com.cs.je.auth.config.jwt;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
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.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
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 com.cs.je.auth.enums.Role;
import com.cs.je.auth.model.User;
/**
 * @author sawai
 *
 */

@Configuration
@EnableAuthorizationServer
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    @Value("${auth.token.time}")
    private int accessTokenValiditySeconds;

    @Value("${refresh.token.time}")
    private int refreshTokenValiditySeconds;

    @Value("${security.oauth2.resource.id}")
    private String resourceId;

    @Value("${trusted.app.name}")
    private String trustedAppName;

    @Value("${trusted.app.secret}")
    private String trustedAppSecret;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private CustomAccessTokenConverter customAccessTokenConverter;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        endpoints
                .authenticationManager(this.authenticationManager)
                .tokenServices(tokenServices())
                .tokenStore(tokenStore())
                .accessTokenConverter(accessTokenConverter());

    }

    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomTokenEnhancer();
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
        // we're allowing access to the token only for clients with 'ROLE_TRUSTED_CLIENT' authority
                //.tokenKeyAccess("permitAll()")
                .tokenKeyAccess("hasAuthority('ROLE_TRUSTED_CLIENT')")
                .checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient(trustedAppName)
                    .authorizedGrantTypes("client_credentials", "password", "refresh_token")
                    .authorities("ROLE_TRUSTED_CLIENT")
                    .scopes("read", "write")
                    .resourceIds(resourceId)
    //                .accessTokenValiditySeconds(accessTokenValiditySeconds)
    //               .refreshTokenValiditySeconds(refreshTokenValiditySeconds)
                    .secret(trustedAppSecret);
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        System.out.println("3333333333333");
        DefaultAccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
        tokenConverter.setUserTokenConverter(new DefaultUserAuthenticationConverter() {
            @Override
            public Authentication extractAuthentication(Map<String, ?> map) {
                Authentication authentication = super.extractAuthentication(map);
                System.out.println("222222222222");
                // User is my custom UserDetails class
                User user = new User();
                user.setTenantId(map.get("tenantId").toString());
                user.setEmail(map.get("email").toString());
                user.setId(map.get("id").toString());
                //user.setPassword(map.get("password").toString());
                //System.out.println("date " + );
                Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
                authorities.addAll(authentication.getAuthorities());
                user.setGrantedAuthorities(authorities);
                user.setRole(Role.valueOf(authorities.iterator().next().toString()));
                //user.setSpecialKey(map.get("specialKey").toString());
                return new UsernamePasswordAuthenticationToken(user,
                        authentication.getCredentials(), authentication.getAuthorities());
            }
        });

        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("key");
        converter.setAccessTokenConverter(customAccessTokenConverter);
        converter.setAccessTokenConverter(tokenConverter);
        return converter;
    }    

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
        defaultTokenServices.setRefreshTokenValiditySeconds(refreshTokenValiditySeconds);
        defaultTokenServices.setReuseRefreshToken(false);
        defaultTokenServices.setTokenEnhancer(tokenEnhancerChain);
        return defaultTokenServices;
    }    
}

Here is Custom Token Enhance: 这是自定义令牌增强:

package com.cs.je.auth.config.jwt;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;

import com.cs.je.auth.enums.Role;
import com.cs.je.auth.model.User;
import com.cs.je.auth.rest.api.call.CustomRestTemplate;
import com.cs.je.auth.service.UserService;
import com.cs.je.auth.utils.EncTokenUtils;
import com.cs.je.auth.utils.UserUtils;

/**
 * @author sawai
 *
 */

@Component
public class CustomTokenEnhancer implements TokenEnhancer {

    @Autowired
    private UserService userService;

    @Autowired
    private CustomRestTemplate customRestTemplate;

    @Value("${microservice.company.protocol}")
    private String protocol;

    @Value("${microservice.company.port}")
    private String port;

    @Value("${microservice.company.ip}")
    private String ipAddress;

    @Value("${microservice.company.user.api}")
    private String userCreateUrl;

    @Autowired
    private TokenStore tokenStore;

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        Map<String, Object> additionalInfo = new HashMap<>();
        if (authentication != null) {
            User user = (User)authentication.getPrincipal();
            additionalInfo.put("email", user.getEmail());
            additionalInfo.put("tenantId", user.getTenantId());
            additionalInfo.put("id", user.getId());
            if (user.isSystemGeneratedPassword()) {
                additionalInfo.put("systemGeneratedPassword", true);
            }

            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            System.out.println(accessToken.getRefreshToken());
            System.out.println(accessToken.getRefreshToken().getValue());
            System.out.println(accessToken.getTokenType());


            /*if (user.getRole().equals(Role.ROLE_ADMIN) || user.getRole().equals(Role.ROLE_USER)) {
                 String token = accessToken.toString();
                 try {
                    System.out.println("before call");
                    //ResponseEntity<Object> responseEntity = customRestTemplate.exchange(protocol + "://" + ipAddress + ":" + port + userCreateUrl + "/" + user.getId() + "/last-loggedOn", token, EncTokenUtils.getEncToken(user.getEmail()), HttpMethod.PUT, null);
                    System.out.println("successfull");
                 } catch (Exception e) {
                    e.printStackTrace();
                } 
            }*/
            System.out.println("1111111111");
        }
        return accessToken;
    }
}

Security Config 安全配置

package com.cs.je.auth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.cs.je.auth.constant.Constants;
import com.cs.je.auth.enums.Role;
import com.cs.je.auth.model.User;
import com.cs.je.auth.repository.UserRepository;
import com.cs.je.auth.service.UserService;
/**
 * @author sawai
 *
 */
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Autowired
    private UserRepository userRepository;

    /*@Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll()
        .antMatchers("/").permitAll()
        .antMatchers(HttpMethod.POST ,"/user/**").hasAnyAuthority("ROLE_SUPER_USER", "ROLE_ADMIN")
        .anyRequest().authenticated();

        httpSecurity.csrf().disable();
        httpSecurity.headers().frameOptions().disable();
        httpSecurity.requestCache().requestCache(new NullRequestCache());
        httpSecurity.httpBasic();
        //httpSecurity.addFilterBefore(CORSFilter, ChannelProcessingFilter.class);
    }*/

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder);

        if (userRepository.count() < 1) {
            User user = new User();
            user.setEmail("jeAdmin@email.com");
            user.setPassword("jeAdminUser");
            user.setTenantId(Constants.JE_TENANT_ID);
            user.setRole(Role.ROLE_SUPER_USER);
            user.setValidate(true);
            userService.create(user, null);
        }
     }

    @Override
    public void configure(WebSecurity webSecurity) {
        webSecurity.ignoring().antMatchers("/api/candidate/**");
        webSecurity.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
        webSecurity.ignoring().antMatchers("/api/company/**");
        webSecurity.ignoring().antMatchers("/api/forgotPassword/**");
        //webSecurity.ignoring().antMatchers(HttpMethod.POST, "/oauth/**");
    }
}

ResourceConfig.java ResourceConfig.java

package com.cs.je.auth.config.jwt;
/**
 * @author sawai
 *
 */

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
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.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.savedrequest.NullRequestCache;
import com.cs.je.auth.filter.CORSFilter;

@Configuration 
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {

    @Value("${security.oauth2.resource.id}")
    private String resourceId;

    // The DefaultTokenServices bean provided at the AuthorizationConfig
    @Autowired
    private DefaultTokenServices tokenServices;

    // The TokenStore bean provided at the AuthorizationConfig
    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private CORSFilter corsFilter;

    // To allow the rResourceServerConfigurerAdapter to understand the token,
    // it must share the same characteristics with AuthorizationServerConfigurerAdapter.
    // So, we must wire it up the beans in the ResourceServerSecurityConfigurer.
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources
                .resourceId(resourceId)
                .tokenServices(tokenServices)
                .tokenStore(tokenStore);
    }


    public void configure(WebSecurity webSecurity) {
        webSecurity.ignoring().antMatchers("/api/candidate/**");
    //  webSecurity.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    //  webSecurity.ignoring().antMatchers(HttpMethod.POST, "/oauth/**");
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http

        .authorizeRequests().antMatchers("/").permitAll().and().authorizeRequests().antMatchers("/console/**")
        .permitAll().and().authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().and()

                // when restricting access to 'Roles' you must remove the "ROLE_" part role
                // for "ROLE_USER" use only "USER"
                //.antMatchers("/api/hello").access("hasAnyRole('USER')")          
                //.antMatchers("/api/admin").hasRole("ADMIN")
                .authorizeRequests().antMatchers(HttpMethod.POST ,"/api/user/**").hasAnyAuthority("ROLE_SUPER_USER", "ROLE_ADMIN")
                // restricting all access to /api/** to authenticated users
                //.antMatchers("/**")
                //.antMatchers("/api/**").authenticated();
                .anyRequest().authenticated();

        http.csrf().disable();
        http.headers().frameOptions().disable();
        http.requestCache().requestCache(new NullRequestCache());
        http.httpBasic();
        http.addFilterBefore(corsFilter, ChannelProcessingFilter.class);
    }
}

All above config is on auth service side. 以上所有配置均在身份验证服务端。 Now when user request for jwt token on auth, then we want to get access-token value on service layer, so i can call company service by secure url calling. 现在,当用户在auth上请求jwt令牌时,我们希望在服务层上获取访问令牌值,因此我可以通过安全的url调用来调用公司服务。

Please guide me how can we get access-token value when user request for jwt token. 请指导我,当用户请求jwt令牌时如何获得访问令牌值。 If you look in CustomTokenEnhancer then we tried to print access-token there by using following statements: 如果您查看CustomTokenEnhancer,那么我们尝试使用以下语句在其中打印访问令牌:

**System.out.println(accessToken.getRefreshToken());
System.out.println(accessToken.getRefreshToken().getValue());
System.out.println(accessToken.getTokenType());**

But values are similar to: 642e0cf2-9214-42d8-ae85-29e5cdfccef1 But we want actual token here. 但是值类似于: 642e0cf2-9214-42d8-ae85-29e5cdfccef1但是我们在这里需要实际的令牌。

Please guide me. 请指导我。

You can use that method 您可以使用该方法

public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String TOKEN_SEPERATOR = " ";

public static String getAccessToken(){
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    if (requestAttributes instanceof ServletRequestAttributes) {
        HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
        return Arrays.asList(request.getHeader(AUTHORIZATION_HEADER).split(TOKEN_SEPERATOR)).get(1);
    }
    return null;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM