Spring Cloud OAuth 2を使用してライセンスサービスを構築

10216 ワード

転載:https://www.cnblogs.com/fp2952/p/8973613.html 本文は主にspring cloud授権サービスの構築であり、jwt認証を採用する.
1.Spring Security Security OAuth 2の導入2.クラス注記オープン@EnableAuthorizationServer 3.Oauth 2構成クラスの起動
AuthorizationServerConfigurerAdapter
  • ClientDetailsServiceConfigurer:クライアント詳細サービス(ClientDetailServices)を構成するためのものであり、クライアント詳細はここで初期化され、クライアント情報を書き込みまたはデータベースを介して呼び出し詳細情報を格納することができる.
  • AuthorizationServerSecurityConfigurer:トークンエンドポイント(TokenEndpoint)を構成するためのセキュリティ制約
  • AuthorizationServerEndpointsConfigurer:ライセンスおよびトークンサービスを構成するための
  • の主な構成は以下の通りである:ClientDetailsServiceConfigurer(AuthorizationServerConfigurerのコールバック構成)はメモリまたはJDBCを使用してクライアントの詳細サービス(ClientDetailsServices)を実現することができ、Spring Security OAuth 2の構成方法は@Configurationクラス継承AuthorizationServerConfigureAdaterを作成し、void configureを書き換えることである(C l e n t D e tailsServiceConfigurer clients)メソッド、たとえば:
     @Override
     public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
     //   JdbcClientDetailsService       
     clients.withClientDetails(new JdbcClientDetailsService(dataSource));
       }
    
  • トークン管理の構成(JWTAccessTokenConverter)
    JWTAccessTokenConverterはtokenを生成するための変換器であり、tokenトークンはデフォルトで署名されており、リソースサーバはこの署名を検証する必要がある.ここでの暗号化および検証には、対称暗号化、非対称暗号化(公開鍵暗号化)の2つの方法がある.対称暗号化には、認証サーバとリソースサーバが同じkey値を格納する必要があります.対称暗号化ではなく、鍵暗号化を使用して、公開鍵をリソースサーバに暴露して署名することができます.本明細書では、非対称暗号化方式を使用して、AuthOrizationServiceConfigurerAdapterに構成されています.
      @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
            endpoints.authenticationManager(authenticationManager)
                    //   JwtAccessToken   
                    .accessTokenConverter(jwtAccessTokenConverter())
                    // refresh_token  userDetailsService
                    .reuseRefreshTokens(false).userDetailsService(userDetailsService);
                    //.tokenStore(getJdbcTokenStore());
        }
    
        /**
         *            Token    
         * @return
         */
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter() {
    
            final JwtAccessTokenConverter converter = new JwtAccessToken();
            //     
            KeyStoreKeyFactory keyStoreKeyFactory =
                    new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "mypass".toCharArray());
            converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mytest"));
    
            return converter;
        }
    

    JDKツールでJKS証明書ファイルを生成し、keystore.jksをresourceディレクトリのkeytool-genkeypair-alias mytest-keyalg RSA-keypass mypass-keystore keystore.jks-storepass mypassここではJwtAccessTokenをカスタマイズして追加ユーザー情報を追加します
    /**
     * Created by fp295 on 2018/4/16.
     *    JwtAccessToken   
     */
    
        public class JwtAccessToken extends JwtAccessTokenConverter {
    
        /**
         *   token
         * @param accessToken
         * @param authentication
         * @return
         */
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            DefaultOAuth2AccessToken defaultOAuth2AccessToken = new DefaultOAuth2AccessToken(accessToken);
    
            //         
            BaseUser baseUser = ((BaseUserDetail) authentication.getPrincipal()).getBaseUser();
            baseUser.setPassword(null);
            //         token     
            defaultOAuth2AccessToken.getAdditionalInformation().put(Constant.USER_INFO, baseUser);
    
            return super.enhance(defaultOAuth2AccessToken, authentication);
        }
    
        /**
         *   token
         * @param value
         * @param map
         * @return
         */
        @Override
        public OAuth2AccessToken extractAccessToken(String value, Map map){
            OAuth2AccessToken oauth2AccessToken = super.extractAccessToken(value, map);
            convertData(oauth2AccessToken, oauth2AccessToken.getAdditionalInformation());
            return oauth2AccessToken;
        }
    
        private void convertData(OAuth2AccessToken accessToken,  Map map) {
            accessToken.getAdditionalInformation().put(Constant.USER_INFO,convertUserData(map.get(Constant.USER_INFO)));
    
        }
    
        private BaseUser convertUserData(Object map) {
            String json = JsonUtils.deserializer(map);
            BaseUser user = JsonUtils.serializable(json, BaseUser.class);
            return user;
        }
    }
    

    JwtAccessTokenクラスではauthenticationのgetPrincipal(実際にはUserDetailsインタフェース)からユーザ情報を取得するので、独自のUserDetailsを実現する必要があります
    /**
     * Created by fp295 on 2018/4/29.
     *   org.springframework.security.core.userdetails.User 
     */
    public class BaseUserDetail implements UserDetails, CredentialsContainer {
    
        private final BaseUser baseUser;
        private final org.springframework.security.core.userdetails.User user;
    
        public BaseUserDetail(BaseUser baseUser, User user) {
            this.baseUser = baseUser;
            this.user = user;
        }
    
    
        @Override
        public void eraseCredentials() {
            user.eraseCredentials();
        }
    
        @Override
        public Collection extends GrantedAuthority> getAuthorities() {
            return user.getAuthorities();
        }
    
        @Override
        public String getPassword() {
            return user.getPassword();
        }
    
        @Override
        public String getUsername() {
            return user.getUsername();
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return user.isAccountNonExpired();
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return user.isAccountNonLocked();
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return user.isCredentialsNonExpired();
        }
    
        @Override
        public boolean isEnabled() {
            return user.isEnabled();
        }
    
        public BaseUser getBaseUser() {
            return baseUser;
        }
    }
    

    認可エンドポイントオープン
     @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
            oauthServer
                    //   /oauth/token_key         
                    .tokenKeyAccess("permitAll()")
                    //   /oauth/check_token          
                    .checkTokenAccess("isAuthenticated()");
        }
    

    Security構成
    DaoAuthenticationProvider、UserDetailServiceなどの構成が必要
    @Configuration
    @Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        //     UserDetailsService
        @Autowired
        private BaseUserDetailService baseUserDetailService;
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http    //      /login     
                    .formLogin().permitAll()
                    //    
                    .and().logout().logoutUrl("/logout").logoutSuccessUrl("/")
                    //               
                    .and().authorizeRequests().anyRequest().authenticated()
                    //       JWT,       csrf
                    .and().csrf().disable();
        }
    
        /**
         *     
         * @param auth
         */
        @Override
        public void configure(AuthenticationManagerBuilder auth) {
            auth.authenticationProvider(daoAuthenticationProvider());
        }
    
    
        @Bean
        public DaoAuthenticationProvider daoAuthenticationProvider(){
            DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
            //   userDetailsService
            provider.setUserDetailsService(baseUserDetailService);
            //            
            provider.setHideUserNotFoundExceptions(false);
            //   BCrypt     hash
            provider.setPasswordEncoder(new BCryptPasswordEncoder(6));
            return provider;
        }
    }
    

    UserDetailsService実装
    @Service
    public class BaseUserDetailService implements UserDetailsService {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        private BaseUserService baseUserService;
        @Autowired
        private BaseRoleService baseRoleService;
     
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
            //   FeignClient    
            ResponseData baseUserResponseData = baseUserService.getUserByUserName(username);
            if(baseUserResponseData.getData() == null || !ResponseCode.SUCCESS.getCode().equals(baseUserResponseData.getCode())){
                logger.error("      ,   :" + username);
                throw new UsernameNotFoundException("      ,   :" + username);
            }
            BaseUser baseUser = baseUserResponseData.getData();
    
            //   FeignClient    
            ResponseData> baseRoleListResponseData = baseRoleService.getRoleByUserId(baseUser.getId());
            List roles;
            if(baseRoleListResponseData.getData() == null ||  !ResponseCode.SUCCESS.getCode().equals(baseRoleListResponseData.getCode())){
                logger.error("      !");
                roles = new ArrayList<>();
            }else {
                roles = baseRoleListResponseData.getData();
            }
    
            //         
            List authorities = new ArrayList();
            roles.forEach(e -> {
                //     、     GrantedAuthority,   GrantedAuthority  
                GrantedAuthority authority = new SimpleGrantedAuthority(e.getRoleCode());
                authorities.add(authority);
            
            });
    
            //            User
            org.springframework.security.core.userdetails.User user =  new org.springframework.security.core.userdetails.User(baseUser.getUserName(),
                    baseUser.getPassword(), isActive(baseUser.getActive()), true, true, true, authorities);
            return new BaseUserDetail(baseUser, user);
        }
    
        private boolean isActive(int active){
            return active == 1 ? true : false;
        }
    }
    

    認証サーバーの検証http://127.0.0.1:8080/oauth/authorize?client_id=clientId&response_type=code&redirect_uri=www.baidu.com
    注意:client_id:データベースに格納されているclient_id、response_type:デッドコード
    リンクして車に戻ってspring securityの簡単なログインページに入り、
    アカウントのパスワードを入力して、UserDetailsServiceが取得するユーザーのためにloginをクリックして、簡単な授権ページに入って、Authorizeをクリックして、redirect_uriにリダイレクトして、codeパラメータを持っています:http://www.baidu.com?code=rTKETX postリクエストtoken:
    なお、ここでは、Basic xxxがclient_id:client_secretのbase 64符号化の値であるAuthorizationリクエストヘッダを追加する必要がある.