diff --git a/.drone.yml b/.drone.yml
new file mode 100644
index 00000000..925a22e4
--- /dev/null
+++ b/.drone.yml
@@ -0,0 +1,13 @@
+---
+kind: pipeline
+type: exec
+name: default
+
+platform:
+ os: linux
+ arch: amd64
+
+steps:
+ - name: greeting
+ commands:
+ - echo HELLO WORLD! Drone on Docker
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..3cacc9d2
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,496 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = crlf
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+max_line_length = 120
+tab_width = 4
+ij_continuation_indent_size = 8
+ij_formatter_off_tag = @formatter:off
+ij_formatter_on_tag = @formatter:on
+ij_formatter_tags_enabled = false
+ij_smart_tabs = false
+ij_visual_guides = none
+ij_wrap_on_typing = false
+
+[*.java]
+ij_java_align_consecutive_assignments = false
+ij_java_align_consecutive_variable_declarations = false
+ij_java_align_group_field_declarations = false
+ij_java_align_multiline_annotation_parameters = false
+ij_java_align_multiline_array_initializer_expression = false
+ij_java_align_multiline_assignment = false
+ij_java_align_multiline_binary_operation = false
+ij_java_align_multiline_chained_methods = false
+ij_java_align_multiline_extends_list = false
+ij_java_align_multiline_for = true
+ij_java_align_multiline_method_parentheses = false
+ij_java_align_multiline_parameters = true
+ij_java_align_multiline_parameters_in_calls = true
+ij_java_align_multiline_parenthesized_expression = false
+ij_java_align_multiline_records = true
+ij_java_align_multiline_resources = true
+ij_java_align_multiline_ternary_operation = false
+ij_java_align_multiline_text_blocks = false
+ij_java_align_multiline_throws_list = false
+ij_java_align_subsequent_simple_methods = false
+ij_java_align_throws_keyword = false
+ij_java_annotation_parameter_wrap = off
+ij_java_array_initializer_new_line_after_left_brace = false
+ij_java_array_initializer_right_brace_on_new_line = false
+ij_java_array_initializer_wrap = off
+ij_java_assert_statement_colon_on_next_line = false
+ij_java_assert_statement_wrap = off
+ij_java_assignment_wrap = off
+ij_java_binary_operation_sign_on_next_line = false
+ij_java_binary_operation_wrap = off
+ij_java_blank_lines_after_anonymous_class_header = 0
+ij_java_blank_lines_after_class_header = 0
+ij_java_blank_lines_after_imports = 1
+ij_java_blank_lines_after_package = 1
+ij_java_blank_lines_around_class = 1
+ij_java_blank_lines_around_field = 0
+ij_java_blank_lines_around_field_in_interface = 0
+ij_java_blank_lines_around_initializer = 1
+ij_java_blank_lines_around_method = 1
+ij_java_blank_lines_around_method_in_interface = 1
+ij_java_blank_lines_before_class_end = 0
+ij_java_blank_lines_before_imports = 1
+ij_java_blank_lines_before_method_body = 0
+ij_java_blank_lines_before_package = 0
+ij_java_block_brace_style = end_of_line
+ij_java_block_comment_at_first_column = true
+ij_java_builder_methods = none
+ij_java_call_parameters_new_line_after_left_paren = false
+ij_java_call_parameters_right_paren_on_new_line = false
+ij_java_call_parameters_wrap = normal
+ij_java_case_statement_on_separate_line = true
+ij_java_catch_on_new_line = false
+ij_java_class_annotation_wrap = split_into_lines
+ij_java_class_brace_style = end_of_line
+ij_java_class_count_to_use_import_on_demand = 5
+ij_java_class_names_in_javadoc = 1
+ij_java_do_not_indent_top_level_class_members = false
+ij_java_do_not_wrap_after_single_annotation = false
+ij_java_do_while_brace_force = never
+ij_java_doc_add_blank_line_after_description = true
+ij_java_doc_add_blank_line_after_param_comments = false
+ij_java_doc_add_blank_line_after_return = false
+ij_java_doc_add_p_tag_on_empty_lines = true
+ij_java_doc_align_exception_comments = true
+ij_java_doc_align_param_comments = true
+ij_java_doc_do_not_wrap_if_one_line = false
+ij_java_doc_enable_formatting = true
+ij_java_doc_enable_leading_asterisks = true
+ij_java_doc_indent_on_continuation = false
+ij_java_doc_keep_empty_lines = true
+ij_java_doc_keep_empty_parameter_tag = true
+ij_java_doc_keep_empty_return_tag = true
+ij_java_doc_keep_empty_throws_tag = true
+ij_java_doc_keep_invalid_tags = true
+ij_java_doc_param_description_on_new_line = false
+ij_java_doc_preserve_line_breaks = false
+ij_java_doc_use_throws_not_exception_tag = true
+ij_java_else_on_new_line = false
+ij_java_entity_dd_suffix = EJB
+ij_java_entity_eb_suffix = Bean
+ij_java_entity_hi_suffix = Home
+ij_java_entity_lhi_prefix = Local
+ij_java_entity_lhi_suffix = Home
+ij_java_entity_li_prefix = Local
+ij_java_entity_pk_class = java.lang.String
+ij_java_entity_vo_suffix = VO
+ij_java_enum_constants_wrap = off
+ij_java_extends_keyword_wrap = off
+ij_java_extends_list_wrap = off
+ij_java_field_annotation_wrap = split_into_lines
+ij_java_finally_on_new_line = false
+ij_java_for_brace_force = never
+ij_java_for_statement_new_line_after_left_paren = false
+ij_java_for_statement_right_paren_on_new_line = false
+ij_java_for_statement_wrap = off
+ij_java_generate_final_locals = false
+ij_java_generate_final_parameters = false
+ij_java_if_brace_force = never
+ij_java_imports_layout = *,|,javax.**,java.**,|,$*
+ij_java_indent_case_from_switch = true
+ij_java_insert_inner_class_imports = false
+ij_java_insert_override_annotation = true
+ij_java_keep_blank_lines_before_right_brace = 2
+ij_java_keep_blank_lines_between_package_declaration_and_header = 2
+ij_java_keep_blank_lines_in_code = 2
+ij_java_keep_blank_lines_in_declarations = 2
+ij_java_keep_builder_methods_indents = false
+ij_java_keep_control_statement_in_one_line = true
+ij_java_keep_first_column_comment = true
+ij_java_keep_indents_on_empty_lines = false
+ij_java_keep_line_breaks = true
+ij_java_keep_multiple_expressions_in_one_line = false
+ij_java_keep_simple_blocks_in_one_line = false
+ij_java_keep_simple_classes_in_one_line = false
+ij_java_keep_simple_lambdas_in_one_line = false
+ij_java_keep_simple_methods_in_one_line = false
+ij_java_label_indent_absolute = false
+ij_java_label_indent_size = 0
+ij_java_lambda_brace_style = end_of_line
+ij_java_layout_static_imports_separately = true
+ij_java_line_comment_add_space = false
+ij_java_line_comment_at_first_column = true
+ij_java_message_dd_suffix = EJB
+ij_java_message_eb_suffix = Bean
+ij_java_method_annotation_wrap = split_into_lines
+ij_java_method_brace_style = end_of_line
+ij_java_method_call_chain_wrap = off
+ij_java_method_parameters_new_line_after_left_paren = false
+ij_java_method_parameters_right_paren_on_new_line = false
+ij_java_method_parameters_wrap = off
+ij_java_modifier_list_wrap = false
+ij_java_names_count_to_use_import_on_demand = 3
+ij_java_new_line_after_lparen_in_record_header = false
+ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
+ij_java_parameter_annotation_wrap = off
+ij_java_parentheses_expression_new_line_after_left_paren = false
+ij_java_parentheses_expression_right_paren_on_new_line = false
+ij_java_place_assignment_sign_on_next_line = false
+ij_java_prefer_longer_names = true
+ij_java_prefer_parameters_wrap = false
+ij_java_record_components_wrap = normal
+ij_java_repeat_synchronized = true
+ij_java_replace_instanceof_and_cast = false
+ij_java_replace_null_check = true
+ij_java_replace_sum_lambda_with_method_ref = true
+ij_java_resource_list_new_line_after_left_paren = false
+ij_java_resource_list_right_paren_on_new_line = false
+ij_java_resource_list_wrap = off
+ij_java_rparen_on_new_line_in_record_header = false
+ij_java_session_dd_suffix = EJB
+ij_java_session_eb_suffix = Bean
+ij_java_session_hi_suffix = Home
+ij_java_session_lhi_prefix = Local
+ij_java_session_lhi_suffix = Home
+ij_java_session_li_prefix = Local
+ij_java_session_si_suffix = Service
+ij_java_space_after_closing_angle_bracket_in_type_argument = false
+ij_java_space_after_colon = true
+ij_java_space_after_comma = true
+ij_java_space_after_comma_in_type_arguments = true
+ij_java_space_after_for_semicolon = true
+ij_java_space_after_quest = true
+ij_java_space_after_type_cast = true
+ij_java_space_before_annotation_array_initializer_left_brace = false
+ij_java_space_before_annotation_parameter_list = false
+ij_java_space_before_array_initializer_left_brace = false
+ij_java_space_before_catch_keyword = true
+ij_java_space_before_catch_left_brace = true
+ij_java_space_before_catch_parentheses = true
+ij_java_space_before_class_left_brace = true
+ij_java_space_before_colon = true
+ij_java_space_before_colon_in_foreach = true
+ij_java_space_before_comma = false
+ij_java_space_before_do_left_brace = true
+ij_java_space_before_else_keyword = true
+ij_java_space_before_else_left_brace = true
+ij_java_space_before_finally_keyword = true
+ij_java_space_before_finally_left_brace = true
+ij_java_space_before_for_left_brace = true
+ij_java_space_before_for_parentheses = true
+ij_java_space_before_for_semicolon = false
+ij_java_space_before_if_left_brace = true
+ij_java_space_before_if_parentheses = true
+ij_java_space_before_method_call_parentheses = false
+ij_java_space_before_method_left_brace = true
+ij_java_space_before_method_parentheses = false
+ij_java_space_before_opening_angle_bracket_in_type_parameter = false
+ij_java_space_before_quest = true
+ij_java_space_before_switch_left_brace = true
+ij_java_space_before_switch_parentheses = true
+ij_java_space_before_synchronized_left_brace = true
+ij_java_space_before_synchronized_parentheses = true
+ij_java_space_before_try_left_brace = true
+ij_java_space_before_try_parentheses = true
+ij_java_space_before_type_parameter_list = false
+ij_java_space_before_while_keyword = true
+ij_java_space_before_while_left_brace = true
+ij_java_space_before_while_parentheses = true
+ij_java_space_inside_one_line_enum_braces = false
+ij_java_space_within_empty_array_initializer_braces = false
+ij_java_space_within_empty_method_call_parentheses = false
+ij_java_space_within_empty_method_parentheses = false
+ij_java_spaces_around_additive_operators = true
+ij_java_spaces_around_assignment_operators = true
+ij_java_spaces_around_bitwise_operators = true
+ij_java_spaces_around_equality_operators = true
+ij_java_spaces_around_lambda_arrow = true
+ij_java_spaces_around_logical_operators = true
+ij_java_spaces_around_method_ref_dbl_colon = false
+ij_java_spaces_around_multiplicative_operators = true
+ij_java_spaces_around_relational_operators = true
+ij_java_spaces_around_shift_operators = true
+ij_java_spaces_around_type_bounds_in_type_parameters = true
+ij_java_spaces_around_unary_operator = false
+ij_java_spaces_within_angle_brackets = false
+ij_java_spaces_within_annotation_parentheses = false
+ij_java_spaces_within_array_initializer_braces = false
+ij_java_spaces_within_braces = false
+ij_java_spaces_within_brackets = false
+ij_java_spaces_within_cast_parentheses = false
+ij_java_spaces_within_catch_parentheses = false
+ij_java_spaces_within_for_parentheses = false
+ij_java_spaces_within_if_parentheses = false
+ij_java_spaces_within_method_call_parentheses = false
+ij_java_spaces_within_method_parentheses = false
+ij_java_spaces_within_parentheses = false
+ij_java_spaces_within_record_header = false
+ij_java_spaces_within_switch_parentheses = false
+ij_java_spaces_within_synchronized_parentheses = false
+ij_java_spaces_within_try_parentheses = false
+ij_java_spaces_within_while_parentheses = false
+ij_java_special_else_if_treatment = true
+ij_java_subclass_name_suffix = Impl
+ij_java_ternary_operation_signs_on_next_line = false
+ij_java_ternary_operation_wrap = off
+ij_java_test_name_suffix = Test
+ij_java_throws_keyword_wrap = off
+ij_java_throws_list_wrap = off
+ij_java_use_external_annotations = false
+ij_java_use_fq_class_names = false
+ij_java_use_relative_indents = false
+ij_java_use_single_class_imports = true
+ij_java_variable_annotation_wrap = off
+ij_java_visibility = public
+ij_java_while_brace_force = never
+ij_java_while_on_new_line = false
+ij_java_wrap_comments = false
+ij_java_wrap_first_method_in_call_chain = false
+ij_java_wrap_long_lines = true
+
+[.editorconfig]
+ij_editorconfig_align_group_field_declarations = false
+ij_editorconfig_space_after_colon = false
+ij_editorconfig_space_after_comma = true
+ij_editorconfig_space_before_colon = false
+ij_editorconfig_space_before_comma = false
+ij_editorconfig_spaces_around_assignment_operators = true
+
+[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdd,*.wsdl,*.xjb,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
+ij_xml_align_attributes = true
+ij_xml_align_text = false
+ij_xml_attribute_wrap = normal
+ij_xml_block_comment_at_first_column = true
+ij_xml_keep_blank_lines = 2
+ij_xml_keep_indents_on_empty_lines = false
+ij_xml_keep_line_breaks = true
+ij_xml_keep_line_breaks_in_text = true
+ij_xml_keep_whitespaces = false
+ij_xml_keep_whitespaces_around_cdata = preserve
+ij_xml_keep_whitespaces_inside_cdata = false
+ij_xml_line_comment_at_first_column = true
+ij_xml_space_after_tag_name = false
+ij_xml_space_around_equals_in_attribute = false
+ij_xml_space_inside_empty_tag = false
+ij_xml_text_wrap = normal
+ij_xml_use_custom_settings = false
+
+[{*.bash,*.sh,*.zsh}]
+indent_size = 2
+tab_width = 2
+ij_shell_binary_ops_start_line = false
+ij_shell_keep_column_alignment_padding = false
+ij_shell_minify_program = false
+ij_shell_redirect_followed_by_space = false
+ij_shell_switch_cases_indented = false
+ij_shell_use_unix_line_separator = true
+
+[{*.cjs,*.js}]
+ij_continuation_indent_size = 4
+ij_javascript_align_imports = false
+ij_javascript_align_multiline_array_initializer_expression = false
+ij_javascript_align_multiline_binary_operation = false
+ij_javascript_align_multiline_chained_methods = false
+ij_javascript_align_multiline_extends_list = false
+ij_javascript_align_multiline_for = true
+ij_javascript_align_multiline_parameters = true
+ij_javascript_align_multiline_parameters_in_calls = false
+ij_javascript_align_multiline_ternary_operation = false
+ij_javascript_align_object_properties = 0
+ij_javascript_align_union_types = false
+ij_javascript_align_var_statements = 0
+ij_javascript_array_initializer_new_line_after_left_brace = false
+ij_javascript_array_initializer_right_brace_on_new_line = false
+ij_javascript_array_initializer_wrap = off
+ij_javascript_assignment_wrap = off
+ij_javascript_binary_operation_sign_on_next_line = false
+ij_javascript_binary_operation_wrap = off
+ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
+ij_javascript_blank_lines_after_imports = 1
+ij_javascript_blank_lines_around_class = 1
+ij_javascript_blank_lines_around_field = 0
+ij_javascript_blank_lines_around_function = 1
+ij_javascript_blank_lines_around_method = 1
+ij_javascript_block_brace_style = end_of_line
+ij_javascript_call_parameters_new_line_after_left_paren = false
+ij_javascript_call_parameters_right_paren_on_new_line = false
+ij_javascript_call_parameters_wrap = off
+ij_javascript_catch_on_new_line = false
+ij_javascript_chained_call_dot_on_new_line = true
+ij_javascript_class_brace_style = end_of_line
+ij_javascript_comma_on_new_line = false
+ij_javascript_do_while_brace_force = never
+ij_javascript_else_on_new_line = false
+ij_javascript_enforce_trailing_comma = keep
+ij_javascript_extends_keyword_wrap = off
+ij_javascript_extends_list_wrap = off
+ij_javascript_field_prefix = _
+ij_javascript_file_name_style = relaxed
+ij_javascript_finally_on_new_line = false
+ij_javascript_for_brace_force = never
+ij_javascript_for_statement_new_line_after_left_paren = false
+ij_javascript_for_statement_right_paren_on_new_line = false
+ij_javascript_for_statement_wrap = off
+ij_javascript_force_quote_style = false
+ij_javascript_force_semicolon_style = false
+ij_javascript_function_expression_brace_style = end_of_line
+ij_javascript_if_brace_force = never
+ij_javascript_import_merge_members = global
+ij_javascript_import_prefer_absolute_path = global
+ij_javascript_import_sort_members = true
+ij_javascript_import_sort_module_name = false
+ij_javascript_import_use_node_resolution = true
+ij_javascript_imports_wrap = on_every_item
+ij_javascript_indent_case_from_switch = true
+ij_javascript_indent_chained_calls = true
+ij_javascript_indent_package_children = 0
+ij_javascript_jsx_attribute_value = braces
+ij_javascript_keep_blank_lines_in_code = 2
+ij_javascript_keep_first_column_comment = true
+ij_javascript_keep_indents_on_empty_lines = false
+ij_javascript_keep_line_breaks = true
+ij_javascript_keep_simple_blocks_in_one_line = false
+ij_javascript_keep_simple_methods_in_one_line = false
+ij_javascript_line_comment_add_space = true
+ij_javascript_line_comment_at_first_column = false
+ij_javascript_method_brace_style = end_of_line
+ij_javascript_method_call_chain_wrap = off
+ij_javascript_method_parameters_new_line_after_left_paren = false
+ij_javascript_method_parameters_right_paren_on_new_line = false
+ij_javascript_method_parameters_wrap = off
+ij_javascript_object_literal_wrap = on_every_item
+ij_javascript_parentheses_expression_new_line_after_left_paren = false
+ij_javascript_parentheses_expression_right_paren_on_new_line = false
+ij_javascript_place_assignment_sign_on_next_line = false
+ij_javascript_prefer_as_type_cast = false
+ij_javascript_prefer_explicit_types_function_expression_returns = false
+ij_javascript_prefer_explicit_types_function_returns = false
+ij_javascript_prefer_explicit_types_vars_fields = false
+ij_javascript_prefer_parameters_wrap = false
+ij_javascript_reformat_c_style_comments = false
+ij_javascript_space_after_colon = true
+ij_javascript_space_after_comma = true
+ij_javascript_space_after_dots_in_rest_parameter = false
+ij_javascript_space_after_generator_mult = true
+ij_javascript_space_after_property_colon = true
+ij_javascript_space_after_quest = true
+ij_javascript_space_after_type_colon = true
+ij_javascript_space_after_unary_not = false
+ij_javascript_space_before_async_arrow_lparen = true
+ij_javascript_space_before_catch_keyword = true
+ij_javascript_space_before_catch_left_brace = true
+ij_javascript_space_before_catch_parentheses = true
+ij_javascript_space_before_class_lbrace = true
+ij_javascript_space_before_class_left_brace = true
+ij_javascript_space_before_colon = true
+ij_javascript_space_before_comma = false
+ij_javascript_space_before_do_left_brace = true
+ij_javascript_space_before_else_keyword = true
+ij_javascript_space_before_else_left_brace = true
+ij_javascript_space_before_finally_keyword = true
+ij_javascript_space_before_finally_left_brace = true
+ij_javascript_space_before_for_left_brace = true
+ij_javascript_space_before_for_parentheses = true
+ij_javascript_space_before_for_semicolon = false
+ij_javascript_space_before_function_left_parenth = true
+ij_javascript_space_before_generator_mult = false
+ij_javascript_space_before_if_left_brace = true
+ij_javascript_space_before_if_parentheses = true
+ij_javascript_space_before_method_call_parentheses = false
+ij_javascript_space_before_method_left_brace = true
+ij_javascript_space_before_method_parentheses = false
+ij_javascript_space_before_property_colon = false
+ij_javascript_space_before_quest = true
+ij_javascript_space_before_switch_left_brace = true
+ij_javascript_space_before_switch_parentheses = true
+ij_javascript_space_before_try_left_brace = true
+ij_javascript_space_before_type_colon = false
+ij_javascript_space_before_unary_not = false
+ij_javascript_space_before_while_keyword = true
+ij_javascript_space_before_while_left_brace = true
+ij_javascript_space_before_while_parentheses = true
+ij_javascript_spaces_around_additive_operators = true
+ij_javascript_spaces_around_arrow_function_operator = true
+ij_javascript_spaces_around_assignment_operators = true
+ij_javascript_spaces_around_bitwise_operators = true
+ij_javascript_spaces_around_equality_operators = true
+ij_javascript_spaces_around_logical_operators = true
+ij_javascript_spaces_around_multiplicative_operators = true
+ij_javascript_spaces_around_relational_operators = true
+ij_javascript_spaces_around_shift_operators = true
+ij_javascript_spaces_around_unary_operator = false
+ij_javascript_spaces_within_array_initializer_brackets = false
+ij_javascript_spaces_within_brackets = false
+ij_javascript_spaces_within_catch_parentheses = false
+ij_javascript_spaces_within_for_parentheses = false
+ij_javascript_spaces_within_if_parentheses = false
+ij_javascript_spaces_within_imports = false
+ij_javascript_spaces_within_interpolation_expressions = false
+ij_javascript_spaces_within_method_call_parentheses = false
+ij_javascript_spaces_within_method_parentheses = false
+ij_javascript_spaces_within_object_literal_braces = false
+ij_javascript_spaces_within_object_type_braces = true
+ij_javascript_spaces_within_parentheses = false
+ij_javascript_spaces_within_switch_parentheses = false
+ij_javascript_spaces_within_type_assertion = false
+ij_javascript_spaces_within_union_types = true
+ij_javascript_spaces_within_while_parentheses = false
+ij_javascript_special_else_if_treatment = true
+ij_javascript_ternary_operation_signs_on_next_line = false
+ij_javascript_ternary_operation_wrap = off
+ij_javascript_union_types_wrap = on_every_item
+ij_javascript_use_chained_calls_group_indents = false
+ij_javascript_use_double_quotes = true
+ij_javascript_use_explicit_js_extension = global
+ij_javascript_use_path_mapping = always
+ij_javascript_use_public_modifier = false
+ij_javascript_use_semicolon_after_statement = true
+ij_javascript_var_declaration_wrap = normal
+ij_javascript_while_brace_force = never
+ij_javascript_while_on_new_line = false
+ij_javascript_wrap_comments = false
+
+[{*.markdown,*.md}]
+ij_markdown_force_one_space_after_blockquote_symbol = true
+ij_markdown_force_one_space_after_header_symbol = true
+ij_markdown_force_one_space_after_list_bullet = true
+ij_markdown_force_one_space_between_words = true
+ij_markdown_keep_indents_on_empty_lines = false
+ij_markdown_max_lines_around_block_elements = 1
+ij_markdown_max_lines_around_header = 1
+ij_markdown_max_lines_between_paragraphs = 1
+ij_markdown_min_lines_around_block_elements = 1
+ij_markdown_min_lines_around_header = 1
+ij_markdown_min_lines_between_paragraphs = 1
+
+[{*.yaml,*.yml}]
+indent_size = 2
+ij_yaml_align_values_properties = do_not_align
+ij_yaml_autoinsert_sequence_marker = true
+ij_yaml_block_mapping_on_new_line = false
+ij_yaml_indent_sequence_value = true
+ij_yaml_keep_indents_on_empty_lines = false
+ij_yaml_keep_line_breaks = true
+ij_yaml_sequence_on_new_line = false
+ij_yaml_space_before_colon = false
+ij_yaml_spaces_within_braces = true
+ij_yaml_spaces_within_brackets = true
diff --git a/.travis/install.sh b/.travis/install.sh
index 8ce31567..01379366 100644
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -15,7 +15,7 @@ command "ls"
printInfo "[INSTALL] Start to run Maven clean, install…"
# Run the Maven clean install
-./mvnw clean install --batch-mode --show-version -DskipTests=true -Dmaven.javadoc.skip=true -Djib.to.auth.username=$DOCKER_HUB_USERNAME -Djib.to.auth.password=$DOCKER_HUB_PASSWORD
+./mvnw clean install --batch-mode --show-version --quiet -DskipTests=true -Dmaven.javadoc.skip=true -Djib.to.auth.username=$DOCKER_HUB_USERNAME -Djib.to.auth.password=$DOCKER_HUB_PASSWORD
INSTALL_COMMAND_RESULT=$?
if [ "$INSTALL_COMMAND_RESULT" -eq 0 ]; then
printInfo "[INSTALL] Installation succeed. INSTALL_COMMAND_RESULT: $INSTALL_COMMAND_RESULT"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 848f5e64..837406d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,23 +1,485 @@
-# 0.0.1 (2020-12-13)
+# [0.0.2](https://github.com/johnnymillergh/muscle-and-fitness-server/compare/0.0.1...0.0.2) (2021-07-16)
+
+### Bug Fixes
+* **$auth-center:** read nested JSON object as Java
+ object ([af101b2](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/af101b201c43c3d4df7891c46e6d3fd2381443ab))
+* **$MyBatis:** correct interceptors
+ order ([3647951](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/3647951d4019220e181b4281d86e4af2907b961f))
+* **$POM:** add test
+ dependency ([401587d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/401587df23c74e3b245fb7e9cecce666612db93d))
### Build System
-* **$Configuration:** update each environment configuration ([72b6c97](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/72b6c9765dbad7109a05c71689f566899acd9cc6))
-* **$Docker:** build Docker image when it's Maven install ([93ec60d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/93ec60dfb85052d9f76356e9fff6ec926057e4be))
-* **$Docker:** update zipkin container ([df5de9d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/df5de9d5f749239b1e0688d9dac9891bb902be2a))
-* **$Docker:** use 20-bit block private network 172.16.1.0/24 ([44a7450](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/44a7450f5df5fb31110b832995779411bf965b87))
-* **$DockerHub:** change DockerHub repository name ([b6067aa](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b6067aa3967e047ab013b8bec4fc278e222fe43f))
-* **$Eureka:** simplify Eureka configuration ([b74c761](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b74c7617c731d0e2bd91bd789a69d13b4ac5cf59))
-* **$Shell:** add `auto-run-mac.sh` ([5e401d7](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/5e401d790b04b2db740a2513496eb2518dd89c16))
+* **$OpenJDK:** update Adopt OpenJDK version to
+ x86_64-alpine-jre-11.0.10_9 ([84d737a](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/84d737af1c5630845a4ef88b4ef0c51136ab383a))
+* **$Redis:** update redis.conf for redis
+ 6.0.10 ([e522c12](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e522c126f611a88c919ac624f55fa6e5fd82a694))
+
+### Code Refactoring
+
+* **$Docker:** abstract Docker environment variables and common
+ constants ([8cc6a36](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/8cc6a36a80f49d090fe669f086fbd99c928ad55f))
+* **$muscle-and-fitness-server:** enhance validation - @NotEmpty ->
+ @NotBlank ([b4150f1](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b4150f1c42d9a2ca36eb9dca36456d5154aef07c))
+* **$service-registry:** remove
+ module `service-registry` ([61bc7cb](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/61bc7cb0301f7c20f28b11ecde85ada7ab36a56c))
+* **$Starter:** rename `spring-boot`
+ to `spring-cloud` ([2529e45](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/2529e450061eff00b883d5a0544792f818489f63))
+
+### Features
+
+* **$api-gateway:** set HTTP header "
+ X-Username" ([d83fe38](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/d83fe38b968c2d9987466b9df8996778064943ef))
+* **$api-gateway:** support request rate
+ limit ([c0dc896](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c0dc896603ea484de269555dad869558fedf8e3c))
+* **$APIGateway:** add global exception
+ handler ([7bb6ffa](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7bb6ffad68fad643ec1f506f49859e2fdecb7601))
+* **$AuthCenter:** access other service by
+ RestTemplate ([f8df08c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/f8df08c53fec6380fc1457ce01c2b225adfc6eb0))
+* **$AuthCenter:** add API for getting service
+ info ([c0b00f3](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c0b00f3b26fc645d86f085fce5e23becca2e3bd7))
+* **$AuthCenter:** add logout
+ API ([66c6717](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/66c67179c7493343f1f4bfb807c15385c2abb684))
+* **$AuthCenter:** enable Redis
+ cache ([6c14c7b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/6c14c7b83512317b79a9245c7e24bb6feb34c400))
+* **$AuthCenter:** expose login
+ API ([fe3f211](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/fe3f211454df32d907950ab27d7701655bf41683))
+* **$AuthCenter:** get services
+ info ([97aadce](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/97aadcef7e3febbdd1a05403d7f72dc2c23d4c43))
+* **$AuthCenter:** support admin
+ authorization ([6e87a2e](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/6e87a2e9c2ba2debb9e46254e29dbf764553a6a0))
+* **$Authorization:** enhance authorization flow - check HTTP
+ method ([01a50de](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/01a50de49b2354a2d1bd29864e3235ec68a1eaeb))
+* **$Consul:** enable Consul config
+ center ([9887360](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9887360ce74d3028b2f367b7ea8a0f773add08b3))
+* **$Consul:** support Consul; abandon Netflix
+ Eureka ([abc1cf8](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/abc1cf835cdb46d7a23e40f14557c21b5265184d))
+* **$ELK:** integrate ELK
+ stack ([a42e87a](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/a42e87a7691011b391c09f9fb20192a100c3bf22))
+* **$Excel:** add abstract excel import
+ class ([901edbd](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/901edbd6f63b116f53dd942769aba70ef88f93f9))
+* **$gateway:** complete authentication
+ flow ([b0a91e0](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b0a91e048743b76abbe66ce484908c4ea3c212d7))
+* **$gateway:** integrate Spring
+ Security ([f092c6b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/f092c6b3b55baddc2cebfee556c11c001083a145))
+* **$gateway:** make Swagger and Spring Security work
+ together ([c2c4721](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c2c47212e5774cb374b6cf20f127f80f482abcd6))
+* **$Gateway:** add reactive openfeign
+ support ([f0b7567](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/f0b756772e1e63f001ae17230c36e076f81c6e1d))
+* **$Gateway:** add reactive Redis
+ support ([2307c71](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/2307c711a94951b9731f78b3d27b9930f59a2cd4))
+* **$Gateway:** implement non-block
+ authorization ([b94944d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b94944d562f31baa3a6eb3549c0b40d8d17d76f7))
+* **$Gateway:** support ignored URL for WebFlux
+ security ([efb83ad](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/efb83adafa2a2e8491d72577194b73893d5e68ca))
+* **$Jackson:** add DateTime
+ serializer ([69548c4](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/69548c439fb56c1d7dd5d9f2e552a1cc0392929c))
+* **$Java:** handle LocalDateTime, LocalDate and
+ LocalTime ([778e152](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/778e15220e34889e9cad41fe783ece8a601ba86a))
+* **$Minio:** upload resource to
+ Minio ([3dc2dc0](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/3dc2dc0a1e095bca72a224ad9c62749e40d51656))
+* **$MinIO:** integrate
+ MinIO ([4db17c0](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/4db17c0647a7d24aacb49f6b0db3662678ee3d9a))
+* **$Pagination:** abstract page response
+ bean ([28928b8](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/28928b8bee5330081590dc3b3c1d63a1fb0fbf07))
+* **$Quartz:** add greeting Quartz
+ job ([7993f40](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7993f40659a5f31e7aecdfbbbf2b0453f41406ba))
+* **$Quartz:** integrate
+ spring-boot-starter-quartz ([5a6d71d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/5a6d71d99d43461ed68dc1591d481267ba64ea29))
+* **$RabbitMQ:** add RabbitMQ Docker
+ container ([414880d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/414880daa175f7ccf06cf17336935becc49f6f08))
+* **$Starter:** abstract startup
+ analysis ([0802aa2](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/0802aa2008aa47cb2c1b5424e64ff48873b6da7a))
+* **$Starter:** add
+ HttpApiScanHelper.java ([629e066](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/629e06671be275bb7c5e47739fb8efa58d67a35f))
+* **$Starter:** integrate
+ RabbitMQ ([9022f77](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9022f777e53e0df8ce3a38aeca1c72489950d0f7))
+* **$Starter:** intercept SQL
+ exceptions ([9f5a16f](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9f5a16f66b96706c1b1a8334ed66342fcf121ddc))
+* **$Starter:** provide exposing HTTP
+ resources ([4f2ebdc](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/4f2ebdcd31c0df8f17ac3c711baf8164ee4b71a6))
+* **$Starter:** support generating recursive
+ tree ([624e5ab](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/624e5ab887935beeccb0fb6a6329e5fbc3349dc8))
+* **$static-resource-center:** get resource from
+ Minio ([da01f3c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/da01f3cfc07d03304dd7c2320ee17a91970f5f49))
+* **$static-resource-center:** support partial
+ response ([7ddf6a9](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7ddf6a975c6976627543f2a3767b736413d54d67))
+* **$STOMP:** support STOMP over
+ WebSocket ([be76707](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/be767070f3f484a19ca115578cb00f0b4fc30cbf))
+* **$Validation:** support Date and LocalDateTime range
+ validation ([f9898be](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/f9898bec3917beec91b61b826b5fd02f2e388d7a))
+* **$Validation:** support date time range value
+ validation ([96c8b83](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/96c8b83dff2769ecb43c7bcb6f5211f59e34ead4))
+* **$Validation:** support enum value
+ validation ([0951f97](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/0951f974289e639e0da28c055a34a3afd49b597b))
+
+### Performance Improvements
+
+* **$api-gateway:** refine exception
+ handling ([b5e1340](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b5e134022401751f420d10b1ada254ddda686777))
+* **$api-gateway:** refine slf4j
+ Logger ([af590f5](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/af590f5b2b805b8560abfd2dddd4b0e4de72195e))
+* **$ApiGateway:** capture
+ FeignException ([c9cdee4](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c9cdee4d24a635764cb21ddc8c44dcfde18cd39e))
+* **$auth-center:** cache role info by user
+ id ([e9d935b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e9d935b183c05287bbc1c1a78f13a1e6140bbc02))
+* **$auth-center:** cache user info by login
+ token ([2bc9115](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/2bc9115ed0d055a00e87e1820f2bced0caf9b99f))
+* **$auth-center:** reduce injected
+ dependencies ([a12f130](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/a12f130c39af3d8f04b7af54d5b352bf92258676))
+* **$DataSource:** reduce instances of data
+ source ([581ac97](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/581ac97cb2f4fcd1c6f0e87dd6c56c309c9967d8))
+* **$Docker:** update container
+ dependencies ([aca40f6](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/aca40f68da38392e7442aca559b957c3a6225a1e))
+* **$ELK:** disable
+ ELK ([ecdb3e2](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/ecdb3e20d59f77a260bcfa0e3f9547e49125728d))
+* **$Excel:** make `maximumRowCount`
+ configurable ([8865ead](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/8865ead8266c0f356d71ad7fa7cba67e000b19d2))
+* **$Java:** migrate java.util.Date to
+ java.time.LocalDateTime ([a354070](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/a3540706839b6f1d84ed6fed29d569b3626e970f))
+* **$Knife4j:** roll back to
+ 2.0.8 ([3c0ce61](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/3c0ce61247e189de4ef6a21307098cb79a74ccf6))
+* **$maf-mis:** merge micro services as '
+ maf-mis' ([7d7284c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7d7284cd2498ce80fe26d4a8b31f35c807944701))
+* **$MySQL:** Docker supports MySQL cluster based on binary
+ log ([bab526a](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/bab526ab552fb9018b3dd3bd9c2f2dce6f7b5e1a))
+* **$MySQL:** MySQL connection
+ retry ([b076feb](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b076febb0291e9061dd27cb4eb2c5337c66c1e91))
+* **$MySQL:** reduce unnecessary replicate
+ db ([3976af1](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/3976af1bd4dc43b45d0f102f9113d4043298a0d5))
+* **$MySQL:** simplify MySQL configuration for
+ docker-compose ([7f4a017](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7f4a017a41ddb7caa8df85884923e58524e8ad0e))
+* **$MySQL:** support auto start
+ replication ([a52619c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/a52619c97c974963731f03a47ef9fabedf37a556))
+* **$POM:** reduce useless
+ dependencies ([447e072](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/447e072a8132a715672f724a202ec3f71bb11aae))
+* **$POM:** update
+ dependencies ([9ef9708](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9ef97081fd464796993c813d2fec27f4d9cedc6b))
+* **$POM:** update Spring Boot Admin version to
+ 2.4.3 ([ad04895](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/ad048950d48aca490cb3af0c56f0794cffd60353))
+* **$POM:** update Spring Cloud version to
+ 2020.0.2 ([bc2241f](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/bc2241fdeba36fa47594ab041113e964016ad354))
+* **$Spring:** refine CORS
+ configuration ([cbb9c7c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/cbb9c7c56c85f7e1c10a7e6c282502ab65b4c3fa))
+* **$spring-boot-admin:** exclude unnecessary
+ dependencies ([305e12b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/305e12b5a7fcd6a59ec1e0cc79c594c4c1aa8d1e))
+* **$SpringCloud:** update version to
+ 2020.0.3 ([010e2c3](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/010e2c32ddda0130ff5da9b9ed1f2569ab65d50d))
+* **$starter:** define the order of controller
+ advice ([34706c9](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/34706c924d37eb6d79bbe661fb792f0eafb5278e))
+* **$starter:** improve Access Specifier Manipulation
+ issue ([435ea3b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/435ea3bf70d4ef6b0ce6d47de2106ef7326bd62f))
+* **$Starter:** dynamic MinIO
+ client ([7d030a3](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7d030a33af5310f247a403850b790efe59a2e8ec))
+* **$Starter:** dynamic SFTP
+ client ([4c37cc4](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/4c37cc4120c74e294f592ff9b80495eb257b5b92))
+* **$Starter:** enable Okhttp for
+ OpenFeign ([0aec942](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/0aec942dcb4472b77a5028b0a9e3dc04f131f989))
+* **$Starter:** support switching dynamic data source on runtime based on
+ SQL ([7dbcfc9](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7dbcfc956aeef73a4818658de8ac4e2518969888))
+* **$Swagger:** correct Swagger
+ switch ([7804da0](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7804da0257fc8f8e34fa4518f82896e2fc210aaf))
+* **$WebSocket:** use RabbitMQ STOMP as message
+ broker ([c666ba7](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c666ba72c2ffa775900f7b5218cdf96c6218cc9f))
+* update
+ dependencies ([6f55581](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/6f555811df4778a29fa76ae38be7294da2f1959c))
+* **$api-gateway:** add IP key resolver for request rate
+ limiter ([ac7aabc](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/ac7aabcc3a83e471377ab1ccf269ddf808b581c8))
+* **$api-gateway:** pass rate limiter configuration
+ dynamically ([0bd97b0](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/0bd97b0262835ee7bb8b1240cafeec03d4010a1d))
+* **$api-gateway:** set Swagger ignored URL on
+ Consul ([699dd0a](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/699dd0a3da15b9a097de3c3b3829b034848431d2))
+* **$ApiGateway:** enhance global exception
+ handler ([0d3f265](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/0d3f265c58f9b7ed51d3c0ab324338925727e0bc))
+* **$ApiGateway:** handle service not available
+ exception ([235bcb8](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/235bcb8c9c51ba4f28d002512a58b5b1722f4e63))
+* **$ApiGateway:** remove JJWT
+ dependencies ([50c0597](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/50c05973c42b7daba898bbfd00347bd081a64673))
+* **$ApiGateway:** rename module `Gateway`
+ to `API Gateway` ([c367ca3](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c367ca3f8920c7586d219744eecc6dd052cb5a77))
+* **$ApiGateway:** shorten module
+ name ([9d7e759](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9d7e759d514f627264616063745863476ded2f25))
+* **$ApiGateway:** use lombok val
+ annotation ([aec0662](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/aec0662ddd1297aee880fad12d5bb9f3690f2471))
+* **$APIGateway:** handle
+ WebClientResponseException ([8c4cd5a](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/8c4cd5af945391d049a79b4d2605b884dc5cfd8a))
+* **$APIGateway:** refine remote API
+ calling ([4f5a20d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/4f5a20d8d8b4f5b5de463ce2d7fe42c2f0cb3752))
+* **$APIGateway:** simplify global exception
+ error ([ff82751](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/ff8275119895628dce5eceb7644f5facb0747edf))
+* **$auth-center:** add PermissionTypeList for remote
+ API ([6928368](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/6928368c89a9af174bd55331b70faa8a94259656))
+* **$auth-center:** configure ignored
+ service ([78c069b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/78c069b0651e88412cdabf3bad782bf7b31739a6))
+* **$auth-center:** refine API
+ parameter ([b5b5346](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b5b5346e535d76690ffae9a3d43ec4397a3c8611))
+* **$AuthCenter:** customize
+ RedisTemplate ([22c9cfb](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/22c9cfbfdd056b11832e5511acb354214f152d07))
+* **$AuthCenter:** refine null check for getting service
+ info ([fc363fe](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/fc363fecfb875ac9ffde21cc4bbbb0819d4cafd2))
+* **$CMD:** check Java major version before running
+ service ([0d06475](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/0d06475081e6df1a8a6e8f3ffa24a051d21901c4))
+* **$Common:** remove useless
+ dependencies ([1df12c5](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/1df12c53b5c138879e94852cbd993f07ac760a30))
+* **$Consul:** deregister service when
+ unavailable ([d36aac3](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/d36aac3c59e0a40da2c2901d00dd4e5a59108e8b))
+* **$Database:** abstract MyBatis Plus configuration; delete Druid
+ configuration ([e88b4d6](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e88b4d6b669ee4a63ab3d562c78942b6c23538ad))
+* **$Database:** update data source
+ configuration ([d343369](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/d3433699c8fa254d0e976467a57485cd05fdefdf))
+* **$Docker:** restrict container
+ dependencies ([67c968d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/67c968d603cbaa7af32a3d27eccdd8d8845a5820))
+* **$Docker:** simplify docker compose by using environment
+ variables ([3216a95](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/3216a956b40791b8980378a4716129324e0a0f75))
+* **$Docker:** specify Docker container
+ tags ([e416c2c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e416c2c442be55212d956d554c00332edc8feabb))
+* **$Docker:** support Docker health
+ check ([7a2ce2b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7a2ce2b0df74c82b182441a7cfb5cec46d4b9366))
+* **$Docker:** update volume mapping for
+ openzipkin/zipkin-cassandra ([abb784f](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/abb784f2c2e652aaf5709820a8779171323fd0bb))
+* **$Druid:** migrate to druid-spring-boot-starter
+ 1.2.4 ([0a7ca5e](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/0a7ca5e174ec01c70d6e7d4c3fc021b1a189caae))
+* **$ELK:** enable elasticsearch
+ security ([bbe59a9](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/bbe59a90fab66a9ea2a45ceb2271d721dfaa23a0))
+* **$Excel:** make variable declare as var and
+ val ([e07452b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e07452b9eaa541062f59da7ba5285bb53cc8ea35))
+* **$Excel:** translate into
+ English ([60f8cd1](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/60f8cd167c20b7157df0b567282e81dfe40c90ae))
+* **$Exception:** refine global exception
+ handling ([dae962b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/dae962b979384a10770892770753b825e6165b52))
+* **$Gateway:** capture
+ SecurityException ([77d6d34](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/77d6d34b60a73e523619b740d0c07f5291e5accb))
+* **$Gateway:** dynamic web security
+ switch ([b5f4333](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b5f43336185fb2a6b55200eb8f6507e31dac878c))
+* **$Gateway:** reduce unnecessary
+ log ([7ba75c3](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7ba75c30c1acfae01603cd3aac4bebb41adc392f))
+* **$Gateway:** refine access
+ log ([281a958](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/281a958d4a86731db52195bb5078fa072d09cd74))
+* **$Gateway:** refine RBAC
+ process ([fed3ea7](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/fed3ea7a4de6677f5aef1764f82fff3936208dac))
+* **$IO:** use buffered IO stream to reduce IO
+ times ([f6c32ee](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/f6c32ee5f3f6f952392113168948adc4325d2152))
+* **$JVM:** increase JVM heap memory; dump heap on OOM
+ error ([45c528b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/45c528bce812d9dba70c0bcf0160c32ac6aa0ba9))
+* **$Log:** enhance web request log
+ format ([a359d07](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/a359d07c764bf1c83538e8834d79d7dc1193fef2))
+* **$LOGBack:** log file contains
+ HOSTNAME ([60b2b73](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/60b2b731b26ac959ade937a6fe3f9237bc4af0f9))
+* **$LOGBack:** set container
+ hostname ([ac3c130](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/ac3c1304455b66a8f233914cadf1a110b5161b13))
+* **$LOGBack:** set log file by
+ ${spring.application.name} ([ec01c8c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/ec01c8cedf61c01126d9466c9bcb0e899e2bdfdb))
+* **$muscle-and-fitness-server:** define basePackage by groupId; devtools
+ switch ([e8a86b1](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e8a86b182c85278faf989757757478ccab5278b8))
+* **$muscle-and-fitness-server:** update
+ dependencies ([e67a840](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e67a840a0fef09f01e5903f7018872930f62514b))
+* **$MyBatis:** field auto
+ fill ([6497bcc](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/6497bcc4ca2ea913124494e903ac4cf80bd6a5b4))
+* **$MyBatisPlus:** enable logic
+ delete ([e48fafa](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e48fafa45e6ed9111bca6497d493abbd749f2503))
+* **$MyBatisPlus:** update
+ interceptors ([9e3ce5c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9e3ce5cc33ac985b04eb7eaf7175de5bf1078d48))
+* **$OpenJDK:** migrate to
+ adoptopenjdk/openjdk11 ([9b65893](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9b65893a22e845a7775db7f80ec988e6436b6038))
+* **$ORM:** migrate ORM library to
+ spring-boot-starter ([0e66476](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/0e6647615317690a16193f139fa174dbd459b527))
+* **$ORM:** migrate Redis library to
+ spring-boot-starter ([7af0ccc](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7af0ccc612067f2608156cc1bd376fcb8cea8ed8))
+* **$ORM:** migrate sftp-integration to
+ spring-boot-starter ([c860ffa](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c860ffa9ab08ee2aede974484b4c5517ce9c8e0d))
+* **$POI:** close workbook when destroying locale
+ context ([ebebd3e](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/ebebd3eaa482f19c43fef45f9458d88ee16bd9a4))
+* **$POI:** update Apache POI version to
+ 5.0.0 ([7b60af5](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7b60af5ba65113c32c48520e94ac2758326032b2))
+* **$POI:** update Druid version to
+ 1.2.5 ([1c1a033](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/1c1a03311d8dd6d9eb796f929ecf2493a239763a))
+* **$POM:** flatten parent
+ dependencies ([e69537a](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e69537a83c9f610d39e0d2e0d124dc7e0a115465))
+* **$POM:** refine dependency
+ structure ([d82c393](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/d82c393f4161e3b1266d1b586a572fdee2c54a4b))
+* **$POM:** update cn.hutool:hutool-all:
+ 5.5.7 ([e7f2193](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e7f2193e76cc15b986692114dddbad935c3f7e1b))
+* **$POM:** update Hutool version to
+ 5.5.8 ([7288bc2](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7288bc2ce02ba658db96bcdb7104f4ec2df7cef0))
+* **$POM:** update hutool-all to
+ 5.5.4 ([e38a37c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e38a37c69b48a4495f1855753571dfe5c77ad0ff))
+* **$POM:** update mybatis-plus version to
+ 3.4.2 ([1eeefcc](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/1eeefcc9b77a3be09528b4caf34c4ce77a3ac110))
+ ,
+ closes [/github.com/baomidou/mybatis-plus/blob/3.0/CHANGELOG.md#v342-20210115](https://github.com//github.com/baomidou/mybatis-plus/blob/3.0/CHANGELOG.md/issues/v342-20210115)
+* **$POM:** update Spring Boot version to
+ 2.3.8.RELEASE ([bc21a41](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/bc21a41db86e2d4af0d79616c4bc2fc1e13f59c2))
+* **$POM:** update Spring Boot version to
+ 2.4.3 ([b955e61](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b955e61fbd7fdc6e47946ca1c1de3498846efbec))
+* **$POM:** update Spring Cloud to
+ Hoxton.SR9 ([9ab311b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9ab311ba65b3babe18e464e39e65c0269d55d124))
+* **$RabbitMQ:** add RabbitMQ health check; set container
+ dependencies ([660bf49](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/660bf49ba8a1d0de4f1ada270fb763e28e99890f))
+ ,
+ closes [/devops.stackexchange.com/questions/12092/docker-compose-healthcheck-for-rabbitmq/12200#12200](https://github.com//devops.stackexchange.com/questions/12092/docker-compose-healthcheck-for-rabbitmq/12200/issues/12200)
+* **$RabbitMQ:** make JSON message converter as
+ default ([1b9bb6d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/1b9bb6ded2005837fe8727eababb36be6ab5175f))
+* **$ReactiveStarter:** abstract access log
+ filter ([d29ba21](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/d29ba212a57e21b6c9f56731e3860b3915296015))
+* **$ReactiveStarter:** abstract
+ beans ([8d1f040](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/8d1f040b937fd7b16ad415815d23b8cb74ad6127))
+* **$ReactiveStarter:** abstract project
+ property ([aafac56](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/aafac56c820fa406f77d6ae0ba6b3c7aba517e41))
+* **$ReactiveStarter:** refine
+ dependencies ([f8905bb](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/f8905bb74c438a12f8a9fa3aba46d95239bec64a))
+* **$ReactiveStarter:** set HTTP header as
+ application/json ([886124a](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/886124ad66e8f9b3d0f8a6b704c58c0707c5ca29))
+* **$ReactiveStarter:** set the order of access log filter as
+ -500 ([1cb0600](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/1cb06000a936caa2f1a2b310dc085c3a31d3ff47))
+* **$Security:** enhance authentication
+ process ([c897611](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c8976113a101ada7712433e580837226bdb8d49c))
+* **$Sleuth:** add
+ dependency `spring-cloud-starter-sleuth` ([8aba675](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/8aba675ab8c85733256f7561533813043a2b1cae))
+* **$SpringBoot:** enable shutdown
+ gracefully ([6360027](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/63600273bd3b8947bbbdfeeddd07f7278995c800))
+* **$SpringBootAdmin:** don't check Consul service
+ health ([e5c8a3d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e5c8a3df800286d71e8716651cce8256818e7600))
+* **$SpringCloud:** update Spring Cloud version to
+ 2020.0.0 ([18f5843](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/18f5843c5af05a37c8c2481f4e8a3d138ee57644))
+* **$SpringCloud:** update Spring Cloud version to
+ 2020.0.1 ([36ecc33](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/36ecc338781a516e20840726dd0d07fc1f7d6988))
+* **$Starter:** abstract common controller and
+ service ([3ab8943](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/3ab8943e1e2a126cc899f680b7cf18bfaa285820))
+* **$Starter:** abstract
+ GlobalErrorController.java ([e22ca36](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e22ca3617c3077de3b0cd3fbf91c86e146acf589))
+* **$Starter:** abstract project
+ property ([b6996c8](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b6996c86036de985658b4e4675d516fa539382a5))
+* **$Starter:** abstract Redis
+ configuration ([9687151](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9687151989353c4ec4a453f810bde131c278bbba))
+* **$Starter:** abstract rest template
+ configuration ([07dfbff](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/07dfbffc91137d52a1d996742372244b90ac0499))
+* **$Starter:** abstract SFTP and web security
+ configuration ([3306ec4](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/3306ec4defb038e20d6a3294f07e61f4d015be7c))
+* **$Starter:** abstract Swagger 2
+ configuration ([5ae8a56](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/5ae8a564a71c4f2cfbc89ede097ed92f79ca1987))
+* **$Starter:** abstract swagger
+ configuration ([2d27aef](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/2d27aeff84a05ee88e172c92a81fd34776149378))
+* **$Starter:** dynamically init
+ bean `WebRequestLogAspect` ([e3176ad](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e3176aded0ef69aaad569218747591e7cd6bdb2b))
+* **$Starter:** enable Spring Boot async
+ task ([418fc43](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/418fc433857bbc80a7be9af7e48bb388ed468c00))
+* **$Starter:** enhance message
+ format ([be3cc41](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/be3cc41a8833654247b510707f55722286ae7dc7))
+* **$Starter:** migrate static web resources to
+ spring-boot-starter ([83ff9eb](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/83ff9ebca68273ffc19751fc7bee20768dbc4047))
+* **$Starter:** reduce unnecessary access
+ log ([7e8a816](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7e8a816575c3348d6ecdd91612521b7abb270785))
+* **$Starter:** refine
+ dependencies ([bd1e5b3](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/bd1e5b38fbf4180e567add86b7b5d2890464608e))
+* **$Starter:** refine error
+ message ([753946c](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/753946cbd6680ac035edaadcaf0cb81b4af88b4f))
+* **$Starter:** simplify internationalization (
+ i18n) ([b42bc7b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b42bc7b3812db702dd0d5315ac09e909cfa5bb4a))
+* **$Starter:** support internationalization (
+ i18n) ([1c8b38b](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/1c8b38bff6765f8206c1e3a3bf4725f9f9bec01b))
+* **$Starter:** use lettuce for
+ Redis ([c40c304](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/c40c3042f3bd0e0788159c9cdde681c81b9ef562))
+* **$Swagger:** correct Swagger switch
+ logic ([e72e8de](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/e72e8def0ac935a5ec5cd85cfb75958fbbe2fb83))
+* **$Swagger:** support service
+ filter ([f07e0de](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/f07e0de75020d2a5437932aa62257bcdaf9d2cf2))
+* **$universal-ui:** abstract web pages to sub
+ module `universal-ui` ([68a34d3](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/68a34d343da05644ce8b1d6a569a67bf107b98db))
+
+### Reverts
+
+* **$AuthCenter:** remove
+ TODO ([de11944](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/de119446bd6c6590ab945e1bbcaa89d4e854f548))
+* **$ELK:** enable
+ ELK ([58ca161](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/58ca16111230224c8d9ff73bab2ca594dbdd3fcf))
+
+### BREAKING CHANGES
+
+* **$starter:** improve Access Specifier Manipulation issue
+* **$IO:** improve IO efficiency
+* **$OpenJDK:** update Docker image from adoptopenjdk/openjdk11:x86_64-alpine-jre-11.0.10_9
+* **$Docker:** abstract Docker environment variables and common constants
+
+[skip ci]
+
+* **$ELK:** aggregate logs from all applications
+* **$api-gateway:** refactor MafConfiguration.java; update configuration key
+* **$CMD:** check Java major version before running service
+
+[skip ci]
+
+* **$muscle-and-fitness-server:** enhance validation - @NotEmpty -> @NotBlank
+
+[skip ci]
+
+* **$Starter:** use lettuce for Redis
+* **$api-gateway:** support request rate limit
+* **$Starter:** rename `spring-boot` to `spring-cloud`
+[skip ci]
+
+* **$Docker:** simplify docker compose by using environment variables
+* **$Consul:** enable Consul config center
+* **$service-registry:** remove module `service-registry`
+
+[skip ci]
+
+* **$Consul:** support Consul; abandon Netflix Eureka
+* **$SpringCloud:** update Spring framework dependencies: Spring Cloud 2020.0.0, Spring Boot 2.4.2
+
+[skip ci]
+
+* **$Starter:** reduce package size by migrating static web resources
+
+[skip ci]
+
+* **$LOGBack:** set log file by ${spring.application.name}
+
+[skip ci]
+
+* **$LOGBack:** log file contains HOSTNAME
+
+[skip ci]
+
+* **$Redis:** update redis.conf for redis 6.0.10
+
+[skip ci]
+
+* **$Authorization:** enhanced authorization flow - check HTTP method
+* **$Starter:** rename MAF Spring Boot Starter package name; set bean injection order
+* **$ApiGateway:** abandon custom HttpStatus, use unified Spring Web HttpStatus
+* **$ApiGateway:** remove module `API Portal`; rename module `Gateway` to
+ `API Gateway`
+* **$ReactiveStarter:** abstract access log filter
+* **$Starter:** reduce unnecessary access log
+* **$Gateway:** implement non-block authorization
+* **$muscle-and-fitness-server:** define basePackage by groupId; devtools switch
+
+# 0.0.1 (2020-12-13)
+
+### Build System
+
+* **$Configuration:** update each environment
+ configuration ([72b6c97](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/72b6c9765dbad7109a05c71689f566899acd9cc6))
+* **$Docker:** build Docker image when it's Maven
+ install ([93ec60d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/93ec60dfb85052d9f76356e9fff6ec926057e4be))
+* **$Docker:** update zipkin
+ container ([df5de9d](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/df5de9d5f749239b1e0688d9dac9891bb902be2a))
+* **$Docker:** use 20-bit block private network
+ 172.16.1.0/24 ([44a7450](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/44a7450f5df5fb31110b832995779411bf965b87))
+* **$DockerHub:** change DockerHub repository
+ name ([b6067aa](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b6067aa3967e047ab013b8bec4fc278e222fe43f))
+* **$Eureka:** simplify Eureka
+ configuration ([b74c761](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/b74c7617c731d0e2bd91bd789a69d13b4ac5cf59))
+* **$Shell:**
+ add `auto-run-mac.sh` ([5e401d7](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/5e401d790b04b2db740a2513496eb2518dd89c16))
### Code Refactoring
* **$muscle-and-fitness-server:** remove demo module ([cd6a6d4](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/cd6a6d4d69c8b17708cb1c45811385dd8b458c33))
* **$Project:** change package name, groupId, DockerHub image repository ([4f65ad7](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/4f65ad795d9fdc48f49cfce8d4ab116a85786cb7))
-
### Features
* **$CMD:** add auto-run-windows.cmd ([7e03aa7](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/7e03aa73a4ec3d6220c4256b7b07ccd3b1ea7f63))
@@ -42,7 +504,6 @@
* **$Validation:** throw all validation error ([19546e1](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/19546e126e111e77fa3deb69fc6c8b8db301398f))
* **$WebLog:** support web log for all HTTP methods ([9de3114](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/9de31148bc95375a5f29cd76f3022e60df8fc4f2))
-
### Performance Improvements
* **$API-Portal:** use var and val for local variables ([ff54ca5](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/ff54ca5cdd1e6da0f98fc81845ae4ecfe62b205a))
@@ -76,7 +537,6 @@
* **$VarAndVal:** synchronize codes - WebRequestLogAspect.java ([f38dded](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/f38ddedea3a7998141ce7e4e1008c9c60d500481))
* **$WebLog:** trim printed JSON string ([48e7984](https://github.com/johnnymillergh/muscle-and-fitness-server/commit/48e79844627f9b06d9316504176ef4c58860969a))
-
### BREAKING CHANGES
* **$Project:** abstract common configuration into custom starter
diff --git a/LICENSE b/LICENSE
index 6c31e43e..56243e83 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2020 Johnny Miller (鍾俊)
+ Copyright 2020 Johnny Miller (锺俊)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index 039dc102..b520bc16 100644
--- a/README.md
+++ b/README.md
@@ -26,35 +26,43 @@ Here is the highlights of **Muscle and Fitness Server**:
2. [Spring Cloud](https://spring.io/projects/spring-cloud) Feature:
- - Eureka - Service registration and discovery.
-
+ - Consul - Service registration and discovery.
+ - Spring Cloud Gateway - API Gateway on top of Spring WebFlux. Provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.
+ - Spring Cloud OpenFeign - Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations. Enhanced connection by Okhttp 3.
- Spring Boot Admin - Admin UI for administration of spring boot applications.
+ - Zipkin - a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in service architectures.
- - Spring Cloud OpenFeign - Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations.
+3. Secured API. RBAC control by API gateway and Auth Center. JWT authentication, and RBAC authorization.
- - Spring Cloud Gateway - provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.
+4. Higher-level packaging other libraries: `Spring Cloud Starter`, auto configuration for Spring Cloud services.
- - Zipkin - a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in service architectures.
+5. MySQL cluster support. Multi data source. Dynamic SQL read-write isolation. MyBatis-Plus is the integrated ORM library.
+
+6. Redis 6.x support.
+
+7. Docker, Rancher Kubernetes support. Google JIB for building Docker container images.
-3. Docker support.
+8. OSS service, based on Minio and SFTP integration.
-4. Multi-environment support.
+9. STOMP over WebSocket (SockJS), real time messaging, based on RabbitMQ STOMP message broker.
-5. SFTP integration.
+10. Quartz support. Distributed job scheduling, based on JDBC.
-6. API visualization. Enhanced Swagger API documentation.
+11. Multi-environment support.
-7. Log compression.
+12. API visualization. Enhanced Swagger API documentation.
-8. Request log.
+13. Log compression. ELK log aggregation.
-9. Method Argument Validation Aspect.
+14. Request log.
-10. Docker container log persistence.
+15. Method Argument Validation Aspect.
-11. Startup statistics.
+16. Docker container log persistence.
-12. Customized startup banner.
+17. Startup statistics.
+
+18. Customized startup banner.
## Usage
@@ -68,6 +76,59 @@ Here is the highlights of **Muscle and Fitness Server**:
3. Click the green triangle to Run.
+## Useful Commands
+
+### Maven
+
+1. Compile:
+
+ ```shell
+ $ mvn clean validate compile --batch-mode --show-version --quiet -f pom.xml
+ ```
+
+2. Package:
+
+ ```shell
+ $ mvn clean package --batch-mode --show-version --quiet -f pom.xml
+ ```
+
+3. Set Version:
+
+ ```sh
+ $ mvn versions:set -DgenerateBackupPoms=false -f pom.xml
+ ```
+
+4. Build Docker Images:
+
+ ```shell
+ $ mvn clean verify --batch-mode --show-version --quiet -f pom.xml
+ ```
+
+### Conventional Changelog CLI
+
+1. Install global dependencies (optional if installed):
+
+ ```
+ npm install -g conventional-changelog-cli
+ ```
+
+2. This will *not* overwrite any previous changelogs. The above generates a changelog based on commits since the last semver tag that matches the pattern of "Feature", "Fix", "Performance Improvement" or "Breaking Changes".
+
+ ```
+ conventional-changelog -p angular -i CHANGELOG.md -s
+ ```
+
+3. If this is your first time using this tool and you want to generate all previous changelogs, you could do:
+
+ ```
+ conventional-changelog -p angular -i CHANGELOG.md -s -r 0
+ ```
+
+## CI (Continuous Integration)
+
+- [Travis CI](https://travis-ci.com/github/johnnymillergh/media-streaming) is for publishing Docker Hub images of SNAPSHOT and RELEASE.
+- [GitHub Actions](https://github.com/johnnymillergh/media-streaming/actions) is for checking dependency updates and tests.
+
## Maintainers
[@johnnymillergh](https://github.com/johnnymillergh).
@@ -94,4 +155,3 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
2020 - Present
-
diff --git a/gateway/README.md b/api-gateway/README.md
similarity index 100%
rename from gateway/README.md
rename to api-gateway/README.md
diff --git a/exercise-mis/auto-run-windows.cmd b/api-gateway/auto-run-windows.cmd
similarity index 77%
rename from exercise-mis/auto-run-windows.cmd
rename to api-gateway/auto-run-windows.cmd
index cd3242c5..2b4a7fc1 100644
--- a/exercise-mis/auto-run-windows.cmd
+++ b/api-gateway/auto-run-windows.cmd
@@ -16,8 +16,10 @@ chcp 65001
@REM #################### Configurable Environment Variables ###################
SET skipGitPull=true
SET skipMavenBuild=true
+SET minimalJavaMajorVersion=11
+SET javaExe=C:\Users\Johnny\.sdkman\candidates\java\11.0.10.hs-adpt\bin\java.exe
SET mavenActiveProfile="development-local"
-SET javaParameter=-Dfile.encoding=UTF-8 -Xms256m -Xmx256m
+SET javaParameter=-Xms256m -Xmx256m -Dfile.encoding=UTF-8 -Dspring.cloud.consul.host=localhost
GOTO:MAIN
@@ -55,6 +57,22 @@ EXIT /B 0
@REM ############################ Custom Functions #############################
+@REM Check Java major version
+:checkJavaMajorVersion
+CALL :logWarn "Start to Check Java major version…"
+%javaExe% -version 1>nul 2>nul || (
+ CALL :logError "Java is not installed!"
+ EXIT /B 2
+)
+for /f tokens^=2-6^ delims^=.-_+^" %%j in ('%javaExe% -fullversion 2^>^&1') do set "currentJavaMajorVersion=%%j"
+CALL :logWarn "Got current Java major version number: %currentJavaMajorVersion%"
+if %currentJavaMajorVersion% LSS %minimalJavaMajorVersion% (
+ CALL :logError "Current Java version is too low, at least OpenJDK %minimalJavaMajorVersion% is needed"
+ EXIT /B 1
+)
+CALL :logInfo "Passed Java major version cheking"
+EXIT /B 0
+
@REM Pull the latest code of current branch from Git.
:gitPull
git pull
@@ -76,7 +94,7 @@ EXIT /B 0
CALL :gitPull
)
CALL :logInfo "[PRE-BUILD] Java Version Information"
- CALL java -version
+ CALL %javaExe% -version
CALL :logInfo "[PRE-BUILD] Maven Version Information"
CALL mvn -v
CALL :logInfo "[PRE-BUILD] Current directory:"
@@ -113,7 +131,7 @@ EXIT /B 0
)
CALL :logWarn "[RUN] Found JAR: %jarFileName%"
CALL :setTerminalTitle %jarFileName%
- SET runJarCommand=java %javaParameter% -Dspring.profiles.active=%mavenActiveProfile% -jar target\%jarFileName%
+ SET runJarCommand=%javaExe% %javaParameter% -Dspring.profiles.active=%mavenActiveProfile% -jar target\%jarFileName%
CALL :logWarn "[RUN] Execute command: %runJarCommand%"
CALL %runJarCommand%
EXIT /B 0
@@ -121,6 +139,14 @@ EXIT /B 0
@REM ############################# MAIN Procedures #############################
:MAIN
cls
+
+@REM Check Java major version
+CALL :checkJavaMajorVersion
+if %ERRORLEVEL% NEQ 0 (
+ CALL :logError "Failed to check Java major version!"
+ EXIT /B %ERRORLEVEL%
+)
+
@REM Pre-build phrase (Display version, Git pull)
CALL :executePreBuildPhase
if %ERRORLEVEL% NEQ 0 (
diff --git a/gateway/pom.xml b/api-gateway/pom.xml
similarity index 69%
rename from gateway/pom.xml
rename to api-gateway/pom.xml
index 0aa3ee96..ebba2a63 100644
--- a/gateway/pom.xml
+++ b/api-gateway/pom.xml
@@ -1,20 +1,16 @@
-
4.0.0
- gateway
- Muscle and Fitness Server :: Gateway
- Gateway for Muscle and Fitness microservices.
-
- 11
- 8080
-
+ api-gateway
+ Muscle and Fitness Server :: API Gateway
+ API Gateway for Muscle and Fitness microservices.
com.jmsoftware.maf
muscle-and-fitness-server
- 0.0.1
+ 0.0.2
@@ -23,22 +19,31 @@
org.springframework.boot
spring-boot-maven-plugin
+
+
+ build-info
+ compile
+
+ build-info
+
+
+
com.google.cloud.tools
jib-maven-plugin
- 2.2.0
+ ${jib-maven-plugin.version}
-
+
buildAndPushDockerImagePhase
@@ -50,8 +55,8 @@
-
- openjdk:11.0.9.1-jre-slim
+
+ adoptopenjdk/openjdk11:${adoptopenjdk11.tag}
docker.io/ijohnnymiller/${project.parent.artifactId}.${project.artifactId}
@@ -66,7 +71,7 @@
-Dfile.encoding=${project.build.sourceEncoding}
- ${gateway.port}
+ ${api-gateway.port}
USE_CURRENT_TIMESTAMP
@@ -78,40 +83,37 @@
- org.springframework.cloud
- spring-cloud-starter-gateway
+ com.jmsoftware.maf
+ reactive-spring-cloud-starter
+
org.springframework.cloud
- spring-cloud-starter-netflix-eureka-client
+ spring-cloud-starter-gateway
+
- org.springframework.cloud
- spring-cloud-starter-zipkin
+ com.github.xiaoymin
+ knife4j-spring-boot-starter
+ ${knife4j.version}
+
- com.jmsoftware.maf
- common
- 0.0.1
+ org.springframework.boot
+ spring-boot-starter-test
+ test
- org.springframework.boot
- spring-boot-starter-web
+ org.junit.vintage
+ junit-vintage-engine
-
-
- de.codecentric
- spring-boot-admin-starter-client
- ${spring-boot-admin.version}
-
-
- com.github.xiaoymin
- knife4j-spring-boot-starter
- ${knife4j.version}
+ io.projectreactor
+ reactor-test
+ test
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.java
new file mode 100644
index 00000000..06ded326
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.java
@@ -0,0 +1,33 @@
+package com.jmsoftware.maf.apigateway;
+
+import com.jmsoftware.maf.reactivespringcloudstarter.helper.SpringBootStartupHelper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.util.StopWatch;
+
+/**
+ *
ApiGatewayApplication
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/22/2020 3:39 PM
+ **/
+@Slf4j
+@EnableDiscoveryClient
+@SpringBootApplication
+public class ApiGatewayApplication {
+ private static final StopWatch STOP_WATCH = new StopWatch();
+ private static SpringBootStartupHelper springBootStartupHelper;
+
+ public ApiGatewayApplication(SpringBootStartupHelper springBootStartupHelper) {
+ ApiGatewayApplication.springBootStartupHelper = springBootStartupHelper;
+ }
+
+ public static void main(String[] args) {
+ STOP_WATCH.start();
+ SpringApplication.run(ApiGatewayApplication.class, args);
+ springBootStartupHelper.stop(STOP_WATCH);
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/remoteapi/AuthCenterRemoteApi.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/remoteapi/AuthCenterRemoteApi.java
new file mode 100644
index 00000000..db33ce06
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/remoteapi/AuthCenterRemoteApi.java
@@ -0,0 +1,117 @@
+package com.jmsoftware.maf.apigateway.remoteapi;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.jmsoftware.maf.common.bean.ResponseBodyBean;
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse;
+import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ *
AuthCenterRemoteApi
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
+ * @date 5/10/20 4:50 PM
+ */
+@Slf4j
+@Service
+@Validated
+@RequiredArgsConstructor
+public class AuthCenterRemoteApi {
+ private static final String SERVICE_NAME = "auth-center";
+ private final WebClient.Builder webClientBuilder;
+
+ /**
+ * Gets user by login token.
+ *
+ * @param loginToken the login token, e.q. username, email or phone number
+ * @return the user by login token
+ */
+ public Mono getUserByLoginToken(@PathVariable String loginToken) {
+ return webClientBuilder
+ .build()
+ .get()
+ .uri(String.format("http://%s/user-remote-api/users/{loginToken}", SERVICE_NAME), loginToken)
+ .retrieve()
+ .bodyToMono(ResponseBodyBean.class)
+ .map(ResponseBodyBean::getData)
+ .map(data -> JSONUtil.toBean(JSONUtil.parseObj(data), GetUserByLoginTokenResponse.class));
+ }
+
+ /**
+ * Gets role list by user id.
+ *
+ * @param userId the user id
+ * @return the role list by user id
+ */
+ public Mono> getRoleListByUserId(@NotNull Long userId) {
+ return webClientBuilder
+ .build()
+ .get()
+ .uri(String.format("http://%s/role-remote-api/roles/{userId}", SERVICE_NAME), userId)
+ .retrieve()
+ .bodyToMono(ResponseBodyBean.class)
+ .map(ResponseBodyBean::getData)
+ .map(data -> JSONUtil.toList(JSONUtil.parseObj(data).getJSONArray("roleList"),
+ GetRoleListByUserIdSingleResponse.class));
+ }
+
+ /**
+ * Get permission list by role id list
+ *
+ * @param payload the payload
+ * @return the response body bean
+ */
+ public Mono> getPermissionListByRoleIdList(@Valid GetPermissionListByRoleIdListPayload payload) {
+ return webClientBuilder
+ .build()
+ .get()
+ .uri(uriBuilder -> uriBuilder
+ .host("auth-center")
+ .path("/permission-remote-api/permissions")
+ .queryParam("roleIdList", StrUtil.join(",", payload.getRoleIdList()))
+ .queryParam("permissionTypeList", StrUtil.join(",", payload.getPermissionTypeList()))
+ .build())
+ .retrieve()
+ .bodyToMono(ResponseBodyBean.class)
+ .map(ResponseBodyBean::getData)
+ .map(data -> JSONUtil.toList(JSONUtil.parseObj(data).getJSONArray("permissionList"),
+ GetPermissionListByRoleIdListResponse.Permission.class));
+ }
+
+ /**
+ * Parse JWT.
+ *
+ * @param authorization the authorization
+ * @return the mono
+ */
+ @GetMapping("/jwt-remote-api/parse")
+ public Mono parse(@NotBlank String authorization) {
+ return webClientBuilder
+ .build()
+ .get()
+ .uri("http://auth-center/jwt-remote-api/parse")
+ .headers(httpHeaders -> httpHeaders.set(HttpHeaders.AUTHORIZATION, authorization))
+ .retrieve()
+ .bodyToMono(ResponseBodyBean.class).map(ResponseBodyBean::getData)
+ .map(data -> JSONUtil.toBean(JSONUtil.parseObj(data), ParseJwtResponse.class));
+ }
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/JwtConfiguration.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/configuration/JwtConfiguration.java
similarity index 57%
rename from auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/JwtConfiguration.java
rename to api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/configuration/JwtConfiguration.java
index 415b4cc2..15199f48 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/JwtConfiguration.java
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/configuration/JwtConfiguration.java
@@ -1,5 +1,6 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
+package com.jmsoftware.maf.apigateway.security.configuration;
+import com.jmsoftware.maf.reactivespringcloudstarter.configuration.MafProjectProperty;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -12,7 +13,7 @@
*
* Ignored request configuration.
*
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
* @date 5/2/20 11:41 PM
**/
@Data
@@ -20,10 +21,19 @@
@Component
@ConfigurationProperties(prefix = "jwt.configuration")
public class JwtConfiguration {
- public JwtConfiguration(ProjectProperty projectProperty) {
- this.signingKey = String.format("%s %s", projectProperty.getProjectParentArtifactId(), projectProperty.getVersion());
+ public static final String TOKEN_PREFIX = "Bearer ";
+ /**
+ * Key prefix of JWT stored in Redis.
+ */
+ private String jwtRedisKeyPrefix;
+
+ public JwtConfiguration(MafProjectProperty mafProjectProperty) {
+ this.signingKey = String.format("%s %s", mafProjectProperty.getProjectParentArtifactId(),
+ mafProjectProperty.getVersion());
log.info("Initiated JWT signing key: {}. The specified key byte array is {} bits", this.signingKey,
this.signingKey.getBytes(StandardCharsets.UTF_8).length * 8);
+ jwtRedisKeyPrefix = String.format("%s:jwt:", mafProjectProperty.getProjectParentArtifactId());
+ log.warn("Initiated 'jwtRedisKeyPrefix': {}", jwtRedisKeyPrefix);
}
/**
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/configuration/WebFluxSecurityConfiguration.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/configuration/WebFluxSecurityConfiguration.java
new file mode 100644
index 00000000..336db14a
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/configuration/WebFluxSecurityConfiguration.java
@@ -0,0 +1,111 @@
+package com.jmsoftware.maf.apigateway.security.configuration;
+
+import cn.hutool.core.util.BooleanUtil;
+import com.google.common.collect.Lists;
+import com.jmsoftware.maf.apigateway.remoteapi.AuthCenterRemoteApi;
+import com.jmsoftware.maf.apigateway.security.impl.*;
+import com.jmsoftware.maf.reactivespringcloudstarter.configuration.MafConfiguration;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.ReactiveAuthenticationManager;
+import org.springframework.security.authorization.ReactiveAuthorizationManager;
+import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+import org.springframework.security.config.web.server.ServerHttpSecurity;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.server.SecurityWebFilterChain;
+import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
+import org.springframework.security.web.server.authorization.AuthorizationContext;
+import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
+import org.springframework.security.web.server.context.ServerSecurityContextRepository;
+
+/**
+ * Description: WebFluxSecurityConfiguration, change description here.
+ *
+ * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/18/2020 3:23 PM
+ * @see
+ * Spring Secirity Reference - Reactive Applications
+ * @see
+ * Securing Spring WebFlux Reactive APIs with JWT Auth
+ * @see
+ * SpringCloud Gateway 整合 Spring Security Webflux 的关键点(痛点解析),及示例项目
+ **/
+@Slf4j
+@Configuration
+@EnableWebFluxSecurity
+@RequiredArgsConstructor
+public class WebFluxSecurityConfiguration {
+ private final MafConfiguration mafConfiguration;
+ private final AuthCenterRemoteApi authCenterRemoteApi;
+
+ @Bean
+ SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http,
+ ServerAuthenticationEntryPoint serverAuthenticationEntryPoint,
+ ServerAccessDeniedHandler serverAccessDeniedHandler,
+ ServerSecurityContextRepository serverSecurityContextRepository,
+ ReactiveAuthenticationManager reactiveAuthenticationManager,
+ ReactiveAuthorizationManager reactiveAuthorizationManager) {
+ if (BooleanUtil.isFalse(this.mafConfiguration.getWebSecurityEnabled())) {
+ log.warn("Web security was disabled.");
+ return http
+ .cors().disable()
+ .csrf().disable()
+ .build();
+ }
+ log.warn("Spring Security will ignore following URLs: {}",
+ Lists.newArrayList(this.mafConfiguration.flattenIgnoredUrls()));
+ return http
+ .cors().disable()
+ .csrf().disable()
+ .formLogin().disable()
+ .httpBasic().disable()
+ .exceptionHandling()
+ .authenticationEntryPoint(serverAuthenticationEntryPoint)
+ .accessDeniedHandler(serverAccessDeniedHandler)
+ .and()
+ // Authentication
+ .securityContextRepository(serverSecurityContextRepository)
+ .authenticationManager(reactiveAuthenticationManager)
+ .authorizeExchange()
+ .pathMatchers(this.mafConfiguration.flattenIgnoredUrls()).permitAll()
+ .pathMatchers(HttpMethod.OPTIONS).permitAll()
+ // Authorization
+ .anyExchange().access(reactiveAuthorizationManager)
+ .and()
+ .build();
+ }
+
+ @Bean
+ public ServerAuthenticationEntryPoint serverAuthenticationEntryPoint() {
+ return new ServerAuthenticationEntryPointImpl();
+ }
+
+ @Bean
+ public ServerAccessDeniedHandler serverAccessDeniedHandler() {
+ return new GatewayServerAccessDeniedHandlerImpl();
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Bean
+ public ServerSecurityContextRepository serverSecurityContextRepository(ReactiveAuthenticationManager reactiveAuthenticationManager) {
+ return new JwtReactiveServerSecurityContextRepositoryImpl(this.mafConfiguration, reactiveAuthenticationManager,
+ this.authCenterRemoteApi);
+ }
+
+ @Bean
+ public ReactiveAuthenticationManager reactiveAuthenticationManager() {
+ return new JwtReactiveAuthenticationManagerImpl(this.authCenterRemoteApi);
+ }
+
+ @Bean
+ public ReactiveAuthorizationManager reactiveAuthorizationManager() {
+ return new RbacReactiveAuthorizationManagerImpl(this.authCenterRemoteApi);
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.java
new file mode 100644
index 00000000..cdcdff44
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.java
@@ -0,0 +1,26 @@
+package com.jmsoftware.maf.apigateway.security.impl;
+
+import com.jmsoftware.maf.reactivespringcloudstarter.util.ResponseUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * Description: GatewayServerAccessDeniedHandlerImpl
+ *
+ * Implementation os gateway server access denied handler
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 9:56 AM
+ **/
+@Slf4j
+public class GatewayServerAccessDeniedHandlerImpl implements ServerAccessDeniedHandler {
+ @Override
+ public Mono handle(ServerWebExchange exchange, AccessDeniedException denied) {
+ log.error("Access denied! Exception message: {}. Request URL: [{}] {}", denied.getMessage(),
+ exchange.getRequest().getMethod(), exchange.getRequest().getURI());
+ return ResponseUtil.renderJson(exchange, HttpStatus.FORBIDDEN, denied.getMessage(), null);
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.java
new file mode 100644
index 00000000..aafb9141
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.java
@@ -0,0 +1,75 @@
+package com.jmsoftware.maf.apigateway.security.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.jmsoftware.maf.apigateway.remoteapi.AuthCenterRemoteApi;
+import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
+import com.jmsoftware.maf.common.exception.BusinessException;
+import com.jmsoftware.maf.common.exception.SecurityException;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.authentication.*;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsChecker;
+import reactor.core.publisher.Mono;
+
+/**
+ * Description: JwtReactiveAuthenticationManagerImpl
+ *
+ * Implementation of JWT reactive authentication manager
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 9:57 AM
+ **/
+@RequiredArgsConstructor
+public class JwtReactiveAuthenticationManagerImpl implements ReactiveAuthenticationManager {
+ private final static Logger log = LoggerFactory.getLogger(JwtReactiveAuthenticationManagerImpl.class);
+ private final AuthCenterRemoteApi authCenterRemoteApi;
+
+ private final UserDetailsChecker preAuthenticationChecks = user -> {
+ if (!user.isAccountNonLocked()) {
+ log.error("User account is locked");
+ throw new LockedException("User account is locked");
+ }
+
+ if (!user.isEnabled()) {
+ log.error("User account is disabled");
+ throw new DisabledException("User is disabled");
+ }
+
+ if (!user.isAccountNonExpired()) {
+ log.error("User account is expired");
+ throw new AccountExpiredException("User account has expired");
+ }
+ };
+
+ private final UserDetailsChecker postAuthenticationChecks = user -> {
+ if (!user.isCredentialsNonExpired()) {
+ log.error("User account credentials have expired");
+ throw new CredentialsExpiredException("User credentials have expired");
+ }
+ };
+
+ private Mono retrieveUser(String username) {
+ if (StrUtil.isBlank(username)) {
+ log.warn("Authentication failure! Cause: the username mustn't be blank");
+ return Mono.error(
+ new SecurityException(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, "Username mustn't be blank"));
+ }
+ return authCenterRemoteApi.getUserByLoginToken(username)
+ .switchIfEmpty(Mono.error(new BusinessException("Authentication failure! Cause: User not found")))
+ .map(data -> {
+ log.info("Authentication success! Found {}", data);
+ return UserPrincipal.create(data, null, null);
+ });
+ }
+
+ @Override
+ public Mono authenticate(Authentication authentication) {
+ return this.retrieveUser(authentication.getName())
+ .doOnNext(this.preAuthenticationChecks::check)
+ .doOnNext(this.postAuthenticationChecks::check)
+ .map(userDetails -> new UsernamePasswordAuthenticationToken(userDetails, null));
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.java
new file mode 100644
index 00000000..0f6e3a9c
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.java
@@ -0,0 +1,69 @@
+package com.jmsoftware.maf.apigateway.security.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.jmsoftware.maf.apigateway.remoteapi.AuthCenterRemoteApi;
+import com.jmsoftware.maf.apigateway.security.configuration.JwtConfiguration;
+import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
+import com.jmsoftware.maf.common.exception.SecurityException;
+import com.jmsoftware.maf.reactivespringcloudstarter.configuration.MafConfiguration;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.authentication.ReactiveAuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextImpl;
+import org.springframework.security.web.server.context.ServerSecurityContextRepository;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * Description: JwtReactiveServerSecurityContextRepositoryImpl
+ *
+ * Implementation of JWT reactive server security context repository
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 9:58 AM
+ **/
+@Slf4j
+@RequiredArgsConstructor
+public class JwtReactiveServerSecurityContextRepositoryImpl implements ServerSecurityContextRepository {
+ private final MafConfiguration mafConfiguration;
+ private final ReactiveAuthenticationManager authenticationManager;
+ private final AntPathMatcher antPathMatcher = new AntPathMatcher();
+ private final AuthCenterRemoteApi authCenterRemoteApi;
+
+ @Override
+ public Mono save(ServerWebExchange exchange, SecurityContext context) {
+ log.error("Unsupported operation exception: Not supported yet.");
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Mono load(ServerWebExchange exchange) {
+ val request = exchange.getRequest();
+ // Ignore allowed URL
+ for (var ignoredUrl : mafConfiguration.flattenIgnoredUrls()) {
+ if (antPathMatcher.match(ignoredUrl, request.getURI().getPath())) {
+ return Mono.empty();
+ }
+ }
+ val authorization = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
+ if (StrUtil.isBlank(authorization) || !StrUtil.startWith(authorization, JwtConfiguration.TOKEN_PREFIX)) {
+ log.warn("Pre-authentication failure! Cause: `{}` in HTTP headers not found. Request URL: [{}] {}",
+ HttpHeaders.AUTHORIZATION, request.getMethod(), request.getURI());
+ return Mono.error(new SecurityException(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, "JWT Required"));
+ }
+ return authCenterRemoteApi.parse(authorization)
+ .map(parseJwtResponse -> {
+ log.info("parseJwtResponse: {}", parseJwtResponse);
+ val userPrincipal = UserPrincipal.createByUsername(parseJwtResponse.getUsername());
+ val authentication = new UsernamePasswordAuthenticationToken(userPrincipal, null);
+ log.warn("About to authenticate… Authentication is created. {}", authentication);
+ return authentication;
+ }).flatMap(authentication -> this.authenticationManager.authenticate(authentication)
+ .map(SecurityContextImpl::new));
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.java
new file mode 100644
index 00000000..75235ee1
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.java
@@ -0,0 +1,149 @@
+package com.jmsoftware.maf.apigateway.security.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.google.common.collect.Lists;
+import com.jmsoftware.maf.apigateway.remoteapi.AuthCenterRemoteApi;
+import com.jmsoftware.maf.common.constant.MafHttpHeader;
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
+import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
+import com.jmsoftware.maf.common.exception.SecurityException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.ReactiveAuthorizationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.server.authorization.AuthorizationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.util.AntPathMatcher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * Description: RbacReactiveAuthorizationManagerImpl
+ *
+ * Implementation of RBAC (Role-based access control) reactive authorization manager
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 9:54 AM
+ * @see Role-based access control
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class RbacReactiveAuthorizationManagerImpl implements ReactiveAuthorizationManager {
+ private final AntPathMatcher antPathMatcher = new AntPathMatcher();
+ private final AuthCenterRemoteApi authCenterRemoteApi;
+
+ /**
+ * Retrieve roles flux.
+ *
+ * @param userPrincipalMono the user principal mono
+ * @return the flux
+ */
+ private Flux retrieveRoles(Mono userPrincipalMono) {
+ // Get role list by user ID, and then convert to Flux>
+ return userPrincipalMono
+ .flatMap(userPrincipal -> this.authCenterRemoteApi.getRoleListByUserId(userPrincipal.getId()))
+ .flatMapMany(Flux::fromIterable)
+ .switchIfEmpty(Flux.error(new SecurityException(HttpStatus.UNAUTHORIZED, "Roles not assigned!")));
+ }
+
+ /**
+ * Filter roles mono.
+ *
+ * @param roleFlux the role flux
+ * @return the mono
+ */
+ private Mono> mapRole(Flux roleFlux) {
+ return roleFlux
+ .map(GetRoleListByUserIdSingleResponse::getId)
+ .collectList()
+ .switchIfEmpty(roleFlux.map(GetRoleListByUserIdSingleResponse::getId).collectList());
+ }
+
+ /**
+ * Retrieve permissions mono.
+ *
+ * @param roleIdListMono the role id list mono
+ * @return the mono
+ */
+ private Mono> retrievePermissions(Mono> roleIdListMono) {
+ // Get permission list based on the Mono>
+ // auth-center will respond /** for role "admin"
+ return roleIdListMono.flatMap(
+ roleIdList -> {
+ val payload = new GetPermissionListByRoleIdListPayload();
+ payload.setRoleIdList(roleIdList);
+ payload.setPermissionTypeList(Lists.newArrayList(PermissionType.BUTTON));
+ return this.authCenterRemoteApi.getPermissionListByRoleIdList(payload);
+ })
+ .switchIfEmpty(Mono.error(new SecurityException(HttpStatus.FORBIDDEN, "Permission not found!")));
+ }
+
+ @Override
+ public Mono check(Mono authentication, AuthorizationContext object) {
+ val request = object.getExchange().getRequest();
+ val userPrincipalMono = authentication.map(auth -> (UserPrincipal) auth.getPrincipal());
+ val roleFlux = this.retrieveRoles(userPrincipalMono);
+ val roleIdListMono = this.mapRole(roleFlux);
+ val permissionListMono = this.retrievePermissions(roleIdListMono);
+ // Aggregate 2 Mono
+ val zip = Mono.zip(permissionListMono, userPrincipalMono);
+ return zip.map(mapper -> {
+ val permissionList = mapper.getT1();
+ val buttonPermissionList = permissionList.stream()
+ .filter(permission -> StrUtil.isNotBlank(permission.getUrl()))
+ .filter(permission -> StrUtil.isNotBlank(permission.getMethod()))
+ .collect(Collectors.toList());
+ val userPrincipal = mapper.getT2();
+ for (var buttonPermission : buttonPermissionList) {
+ if (this.checkRestfulAccess(buttonPermission, request)) {
+ log.info("Authorization success! Resource [{}] {} is accessible for user(username: {})",
+ request.getMethod(), request.getURI(), userPrincipal.getUsername());
+ request
+ .mutate()
+ .headers(httpHeaders -> httpHeaders.set(MafHttpHeader.X_USERNAME.getHeader(),
+ userPrincipal.getUsername()))
+ .build();
+ return new AuthorizationDecision(true);
+ }
+ }
+ log.warn("Authorization failure! Resource [{}] {} is not accessible for user(username: {})",
+ request.getMethod(), request.getURI(), userPrincipal.getUsername());
+ return new AuthorizationDecision(false);
+ });
+ }
+
+ /**
+ * Check Restful access.
+ *
+ * Check if the URL is matched
+ * Check if the HTTP method is matched
+ *
+ *
+ * @param buttonPermission the button permission
+ * @param request the request
+ * @return true: accessible; false: not accessible
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 1/13/2021 11:04 AM
+ */
+ private boolean checkRestfulAccess(GetPermissionListByRoleIdListResponse.Permission buttonPermission,
+ ServerHttpRequest request) {
+ val urlMatched = this.antPathMatcher.match(buttonPermission.getUrl(), request.getURI().getPath());
+ // "*" is for super user. Super user's permission is like URL: "/**", method: "*"
+ val allMethods = StrUtil.equals(buttonPermission.getMethod(), "*");
+ if (allMethods) {
+ return urlMatched;
+ }
+ val methodMatched = Objects.requireNonNull(request.getMethod()).matches(buttonPermission.getMethod());
+ return urlMatched && methodMatched;
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.java
new file mode 100644
index 00000000..52df39f7
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.java
@@ -0,0 +1,24 @@
+package com.jmsoftware.maf.apigateway.security.impl;
+
+import com.jmsoftware.maf.reactivespringcloudstarter.util.ResponseUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * Description: ServerAuthenticationEntryPointImpl, change description here.
+ *
+ * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/21/2020 9:48 AM
+ **/
+@Slf4j
+public class ServerAuthenticationEntryPointImpl implements ServerAuthenticationEntryPoint {
+ @Override
+ public Mono commence(ServerWebExchange exchange, AuthenticationException e) {
+ log.error("Exception occurred when authenticating! Exception message: {}. Request URL: [{}] {}", e.getMessage(),
+ exchange.getRequest().getMethod(), exchange.getRequest().getURI());
+ return ResponseUtil.renderJson(exchange, HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, e.getMessage(), null);
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/DiscoveryRouteConfiguration.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/DiscoveryRouteConfiguration.java
new file mode 100644
index 00000000..e1a7f243
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/DiscoveryRouteConfiguration.java
@@ -0,0 +1,84 @@
+package com.jmsoftware.maf.apigateway.universal.configuration;
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
+import org.springframework.cloud.gateway.filter.FilterDefinition;
+import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import reactor.core.publisher.Mono;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * Description: DiscoveryRouteConfiguration, change description here.
+ *
+ * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 2/7/2021 1:15 PM
+ **/
+@Slf4j
+@Configuration
+@RequiredArgsConstructor
+public class DiscoveryRouteConfiguration {
+ public static final String REQUEST_RATE_LIMITER_FILTER_NAME = "RequestRateLimiter";
+ /**
+ * The redis-rate-limiter.replenishRate
property is how many requests per second you want a user to
+ * be allowed to do, without any dropped requests. This is the rate at which the token bucket is filled.
+ */
+ public static final String REPLENISH_RATE_KEY = "redis-rate-limiter.replenishRate";
+ /**
+ * The redis-rate-limiter.burstCapacity
property is the maximum number of requests a user is allowed
+ * to do in a single second. This is the number of tokens the token bucket can hold. Setting this value to zero
+ * blocks all requests.
+ */
+ public static final String BURST_CAPACITY_KEY = "redis-rate-limiter.burstCapacity";
+ /**
+ * The redis-rate-limiter.requestedTokens
property is how many tokens a request costs. This is the
+ * number of tokens taken from the bucket for each request and defaults to 1
.
+ */
+ public static final String REQUESTED_TOKENS_KEY = "redis-rate-limiter.requestedTokens";
+ private final DiscoveryLocatorProperties discoveryLocatorProperties;
+ private final RedisRateLimiterConfiguration redisRateLimiterConfiguration;
+
+ /**
+ * Configure
+ * The Redis RateLimiter
.
+ *
+ * The algorithm used is the Token Bucket Algorithm .
+ *
+ * Rate limits bellow 1 request/s
are accomplished by setting replenishRate
to the
+ * wanted number of requests, requestedTokens
to the timespan in seconds and
+ * burstCapacity
to the product of replenishRate
and requestedTokens
, e.g.
+ * setting replenishRate=1
, requestedTokens=60
and burstCapacity=60
will
+ * result in a limit of 1 request/min
.
+ *
+ * @see
+ * The Redis RateLimiter
+ */
+ @PostConstruct
+ void postConstruct() {
+ val filter = new FilterDefinition();
+ filter.setName(REQUEST_RATE_LIMITER_FILTER_NAME);
+ filter.addArg(REPLENISH_RATE_KEY, this.redisRateLimiterConfiguration.getReplenishRate());
+ filter.addArg(BURST_CAPACITY_KEY, this.redisRateLimiterConfiguration.getBurstCapacity());
+ filter.addArg(REQUESTED_TOKENS_KEY, this.redisRateLimiterConfiguration.getRequestedTokens());
+ this.discoveryLocatorProperties.getFilters().add(filter);
+ log.info("Added filter [{}] for discovery services, filters: {}", REQUEST_RATE_LIMITER_FILTER_NAME,
+ this.discoveryLocatorProperties.getFilters());
+ }
+
+ @Bean
+ @Primary
+ public KeyResolver ipKeyResolver() {
+ return exchange -> {
+ val remoteAddress = exchange.getRequest().getRemoteAddress();
+ if (ObjectUtil.isNotNull(remoteAddress)) {
+ return Mono.just(remoteAddress.getHostName());
+ }
+ return Mono.just("unknown-address");
+ };
+ }
+}
diff --git a/gateway/src/main/java/com/jmsoftware/maf/gateway/universal/configuration/RedirectConfiguration.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/RedirectConfiguration.java
similarity index 86%
rename from gateway/src/main/java/com/jmsoftware/maf/gateway/universal/configuration/RedirectConfiguration.java
rename to api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/RedirectConfiguration.java
index 8fe56e1c..eaa16f0a 100644
--- a/gateway/src/main/java/com/jmsoftware/maf/gateway/universal/configuration/RedirectConfiguration.java
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/RedirectConfiguration.java
@@ -1,4 +1,4 @@
-package com.jmsoftware.maf.gateway.universal.configuration;
+package com.jmsoftware.maf.apigateway.universal.configuration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
@@ -17,7 +17,7 @@
*
* Redirect Configuration.
*
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
* @date 2/15/20 11:54 PM
**/
@Slf4j
@@ -30,7 +30,7 @@ private void postConstruct() {
@Bean
public RouterFunction home() {
- return route(GET("/home"), request -> {
+ return route(GET("/"), request -> {
log.info("Redirect to Home page.");
return ServerResponse.temporaryRedirect(URI.create("/static/home.html")).build();
});
@@ -47,7 +47,7 @@ public RouterFunction doc() {
@Bean
public RouterFunction favicon() {
return route(GET("/favicon.ico"), request -> {
- log.info("Redirect to Bootstrap Swagger API documentation.");
+ log.info("Redirect to favicon.");
return ServerResponse.temporaryRedirect(URI.create("/static/icon/favicon.ico")).build();
});
}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/RedisRateLimiterConfiguration.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/RedisRateLimiterConfiguration.java
new file mode 100644
index 00000000..ba22acfc
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/RedisRateLimiterConfiguration.java
@@ -0,0 +1,41 @@
+package com.jmsoftware.maf.apigateway.universal.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * RedisRateLimiterConfiguration
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 3/1/2021 9:59 AM
+ */
+@Data
+@Validated
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = RedisRateLimiterConfiguration.PREFIX)
+public class RedisRateLimiterConfiguration {
+ /**
+ * The constant PREFIX.
+ */
+ public static final String PREFIX = "maf.configuration.redis-rate-limiter";
+ /**
+ * The Replenish rate.
+ */
+ @NotBlank
+ private String replenishRate;
+ /**
+ * The Burst capacity.
+ */
+ @NotBlank
+ private String burstCapacity;
+ /**
+ * The Requested tokens.
+ */
+ @NotBlank
+ private String requestedTokens;
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/SwaggerConfiguration.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/SwaggerConfiguration.java
new file mode 100644
index 00000000..085a24c1
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/SwaggerConfiguration.java
@@ -0,0 +1,31 @@
+package com.jmsoftware.maf.apigateway.universal.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import java.util.Set;
+
+/**
+ * SwaggerConfiguration
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 2/7/2021 3:28 PM
+ **/
+@Data
+@Validated
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = SwaggerConfiguration.PREFIX)
+public class SwaggerConfiguration {
+ public static final String PREFIX = "maf.configuration.swagger";
+ /**
+ * Ignored service id set
+ */
+ @NotEmpty
+ private Set<@NotBlank String> ignoredServiceIds;
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/SwaggerResourceProvider.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/SwaggerResourceProvider.java
new file mode 100644
index 00000000..8d0a8269
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/configuration/SwaggerResourceProvider.java
@@ -0,0 +1,107 @@
+package com.jmsoftware.maf.apigateway.universal.configuration;
+
+import cn.hutool.core.collection.CollUtil;
+import com.jmsoftware.maf.reactivespringcloudstarter.configuration.MafProjectProperty;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.cloud.gateway.route.RouteLocator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger.web.SwaggerResource;
+import springfox.documentation.swagger.web.SwaggerResourcesProvider;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * SwaggerResourceProvider
+ *
+ * Change description here.
+ *
+ * https://blog.csdn.net/ttzommed/article/details/81103609
+ *
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
+ * @date 2/15/20 5:40 PM
+ * @see
+ * 文档聚合业务编码
+ **/
+@Slf4j
+@Primary
+@Component
+@RequiredArgsConstructor
+public class SwaggerResourceProvider implements SwaggerResourcesProvider {
+ private static final String SWAGGER_API_URI = "/v2/api-docs";
+ private static final String LINE_SEPARATOR = System.lineSeparator();
+ private final MafProjectProperty mafProjectProperty;
+ private final RouteLocator routeLocator;
+ private final SwaggerConfiguration swaggerConfiguration;
+
+ /**
+ * Generate Swagger resource.
+ *
+ * @return Swagger resource.
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
+ * @date 2/15/20 11:06 PM
+ */
+ @Override
+ public List get() {
+ val swaggerResourceList = new LinkedList();
+ routeLocator.getRoutes().subscribe(route -> {
+ val serviceName = route.getUri().toString().substring(5).toLowerCase();
+ if (!CollUtil.contains(swaggerConfiguration.getIgnoredServiceIds(), serviceName)) {
+ log.warn("{} found dynamic route. Service name: {}, route: {}", this.getClass().getSimpleName(),
+ serviceName, route);
+ val swaggerResource = new SwaggerResource();
+ swaggerResource.setName(serviceName.toUpperCase());
+ swaggerResource.setLocation(String.format("%s%s", serviceName, SWAGGER_API_URI));
+ swaggerResource.setSwaggerVersion("2.0");
+ log.warn("Exposed Swagger Resource: {}", swaggerResource.toString());
+ swaggerResourceList.add(swaggerResource);
+ }
+ });
+ return swaggerResourceList;
+ }
+
+ @Bean
+ public Docket createRestApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .apiInfo(apiInfo())
+ .select()
+ .apis(RequestHandlerSelectors.basePackage(mafProjectProperty.getBasePackage()))
+ .paths(PathSelectors.any())
+ .build();
+ }
+
+ private ApiInfo apiInfo() {
+ val projectArtifactId = mafProjectProperty.getProjectArtifactId();
+ val version = mafProjectProperty.getVersion();
+ val developerEmail = mafProjectProperty.getDeveloperEmail();
+ val developerUrl = mafProjectProperty.getDeveloperUrl();
+ return new ApiInfoBuilder()
+ .title(String.format("API for %s@%s", projectArtifactId, version))
+ .description(String.format("%s %sArtifact ID: %s%sEnvironment: %s",
+ mafProjectProperty.getDescription(),
+ LINE_SEPARATOR,
+ projectArtifactId,
+ LINE_SEPARATOR,
+ mafProjectProperty.getEnvironment()))
+ .contact(new Contact(String.format("%s, email: %s%sHome page: %s",
+ mafProjectProperty.getDeveloperName(),
+ developerEmail,
+ LINE_SEPARATOR,
+ developerUrl),
+ developerUrl, developerEmail))
+ .version(version)
+ .build();
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/controller/SwaggerResourceController.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/controller/SwaggerResourceController.java
new file mode 100644
index 00000000..d8721332
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/controller/SwaggerResourceController.java
@@ -0,0 +1,63 @@
+package com.jmsoftware.maf.apigateway.universal.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
+import springfox.documentation.swagger.web.*;
+
+
+/**
+ * SwaggerResourceController
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
+ * @date 2/15/20 6:07 PM
+ **/
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/swagger-resources")
+public class SwaggerResourceController {
+ private final SwaggerResourcesProvider swaggerResources;
+ private final ApplicationContext applicationContext;
+
+ @GetMapping("/configuration/security")
+ public Mono> securityConfiguration() {
+ SecurityConfiguration securityConfiguration;
+ try {
+ securityConfiguration = applicationContext.getBean(SecurityConfiguration.class);
+ log.info("Bean [{}] is found, {}", SecurityConfiguration.class.getSimpleName(), securityConfiguration);
+ } catch (BeansException e) {
+ securityConfiguration = SecurityConfigurationBuilder.builder().build();
+ log.warn("Bean [{}] is null, create one: {}", SecurityConfiguration.class.getSimpleName(),
+ securityConfiguration);
+ }
+ return Mono.just(new ResponseEntity<>(securityConfiguration, HttpStatus.OK));
+ }
+
+ @GetMapping("/configuration/ui")
+ public Mono> uiConfiguration() {
+ UiConfiguration uiConfiguration;
+ try {
+ uiConfiguration = applicationContext.getBean(UiConfiguration.class);
+ log.info("Bean [{}] is found, {}", UiConfiguration.class.getSimpleName(), uiConfiguration);
+ } catch (BeansException e) {
+ uiConfiguration = UiConfigurationBuilder.builder().build();
+ log.warn("Bean [{}] is null, create one: {}", UiConfiguration.class.getSimpleName(), uiConfiguration);
+ }
+ return Mono.just(new ResponseEntity<>(uiConfiguration, HttpStatus.OK));
+ }
+
+ @GetMapping("")
+ public Mono> swaggerResources() {
+ return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/handler/GlobalExceptionHandler.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/handler/GlobalExceptionHandler.java
new file mode 100644
index 00000000..68bf123d
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/handler/GlobalExceptionHandler.java
@@ -0,0 +1,94 @@
+package com.jmsoftware.maf.apigateway.universal.handler;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.jmsoftware.maf.common.bean.ResponseBodyBean;
+import com.jmsoftware.maf.common.exception.SecurityException;
+import com.jmsoftware.maf.reactivespringcloudstarter.util.RequestUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * GlobalExceptionHandler
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
+ * @date 12/23/20 7:45 AM
+ **/
+@Slf4j
+@Order(-1)
+@Component
+@RequiredArgsConstructor
+public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
+ private final ObjectMapper objectMapper;
+
+ @Override
+ @SuppressWarnings("NullableProblems")
+ public Mono handle(ServerWebExchange exchange, Throwable ex) {
+ val request = exchange.getRequest();
+ log.error("Exception occurred when [{}] requested access. Exception message: {}. Request URL: [{}] {}",
+ RequestUtil.getRequesterIpAndPort(request), ex.getMessage(), request.getMethod(), request.getURI());
+ val response = exchange.getResponse();
+ if (response.isCommitted()) {
+ return Mono.error(ex);
+ }
+ // Set HTTP header, major browsers like Chrome now comply with the specification and interpret correctly
+ // UTF-8 special characters without requiring a charset=UTF-8 parameter.
+ response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
+ return response.writeWith(Mono.fromSupplier(() -> {
+ val bufferFactory = response.bufferFactory();
+ val responseBody = setResponseBody(response, ex);
+ try {
+ return bufferFactory.wrap(objectMapper.writeValueAsBytes(responseBody));
+ } catch (JsonProcessingException e) {
+ log.warn("Exception occurred when writing response", e);
+ return bufferFactory.wrap(e.getMessage().getBytes(StandardCharsets.UTF_8));
+ }
+ }));
+ }
+
+ /**
+ * Sets response body.
+ *
+ * @param response the response
+ * @param ex the ex
+ * @return the response body
+ */
+ private ResponseBodyBean> setResponseBody(ServerHttpResponse response, Throwable ex) {
+ if (ex instanceof ResponseStatusException) {
+ response.setStatusCode(((ResponseStatusException) ex).getStatus());
+ return ResponseBodyBean.ofStatus(((ResponseStatusException) ex).getStatus());
+ } else if (ex instanceof SecurityException) {
+ HttpStatus status = HttpStatus.valueOf(((SecurityException) ex).getCode());
+ response.setStatusCode(status);
+ return ResponseBodyBean.ofStatus(status, ex.getMessage());
+ } else if (ex instanceof WebClientResponseException) {
+ val exception = (WebClientResponseException) ex;
+ response.setStatusCode(exception.getStatusCode());
+ try {
+ return objectMapper.readValue(exception.getResponseBodyAsString(), ResponseBodyBean.class);
+ } catch (JsonProcessingException e) {
+ log.warn("Exception occurred when writing response. Exception message: {}", e.getMessage());
+ return ResponseBodyBean.ofStatus(exception.getStatusCode(),
+ exception.getResponseBodyAsString(StandardCharsets.UTF_8));
+ }
+ }
+ response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
+ return ResponseBodyBean.ofStatus(HttpStatus.INTERNAL_SERVER_ERROR,
+ String.format("Exception message: %s", ex.getMessage()));
+ }
+}
diff --git a/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/util/package-info.java b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/util/package-info.java
new file mode 100644
index 00000000..c516b5ef
--- /dev/null
+++ b/api-gateway/src/main/java/com/jmsoftware/maf/apigateway/universal/util/package-info.java
@@ -0,0 +1 @@
+package com.jmsoftware.maf.apigateway.universal.util;
diff --git a/api-gateway/src/main/resources/application-development-docker.yml b/api-gateway/src/main/resources/application-development-docker.yml
new file mode 100644
index 00000000..ca768773
--- /dev/null
+++ b/api-gateway/src/main/resources/application-development-docker.yml
@@ -0,0 +1,9 @@
+spring:
+ zipkin:
+ base-url: http://maf-zipkin:9411
+ devtools:
+ add-properties: true
+ redis:
+ host: maf-redis
+ port: 6379
+ password: maf@redis
diff --git a/api-gateway/src/main/resources/application-development-local.yml b/api-gateway/src/main/resources/application-development-local.yml
new file mode 100644
index 00000000..dbdd387e
--- /dev/null
+++ b/api-gateway/src/main/resources/application-development-local.yml
@@ -0,0 +1,13 @@
+spring:
+ devtools:
+ add-properties: true
+ zipkin:
+ base-url: http://localhost:9411
+ redis:
+ host: localhost
+ port: 6379
+ password: maf@redis
+
+maf:
+ configuration:
+ web-security-enabled: false
diff --git a/api-gateway/src/main/resources/application-production.yml b/api-gateway/src/main/resources/application-production.yml
new file mode 100644
index 00000000..15d4a3c7
--- /dev/null
+++ b/api-gateway/src/main/resources/application-production.yml
@@ -0,0 +1,9 @@
+spring:
+ devtools:
+ add-properties: false
+ zipkin:
+ base-url: http://maf-zipkin:9411
+ redis:
+ host: maf-redis
+ port: 6379
+ password: maf@redis
diff --git a/api-gateway/src/main/resources/application-stage.yml b/api-gateway/src/main/resources/application-stage.yml
new file mode 100644
index 00000000..15d4a3c7
--- /dev/null
+++ b/api-gateway/src/main/resources/application-stage.yml
@@ -0,0 +1,9 @@
+spring:
+ devtools:
+ add-properties: false
+ zipkin:
+ base-url: http://maf-zipkin:9411
+ redis:
+ host: maf-redis
+ port: 6379
+ password: maf@redis
diff --git a/api-gateway/src/main/resources/application-test.yml b/api-gateway/src/main/resources/application-test.yml
new file mode 100644
index 00000000..15d4a3c7
--- /dev/null
+++ b/api-gateway/src/main/resources/application-test.yml
@@ -0,0 +1,9 @@
+spring:
+ devtools:
+ add-properties: false
+ zipkin:
+ base-url: http://maf-zipkin:9411
+ redis:
+ host: maf-redis
+ port: 6379
+ password: maf@redis
diff --git a/api-gateway/src/main/resources/application.yml b/api-gateway/src/main/resources/application.yml
new file mode 100644
index 00000000..de382bb4
--- /dev/null
+++ b/api-gateway/src/main/resources/application.yml
@@ -0,0 +1,99 @@
+server:
+ port: @api-gateway.port@
+ tomcat:
+ uri-encoding: @project.build.sourceEncoding@
+ shutdown: GRACEFUL
+ servlet:
+ context-path:
+
+spring:
+ profiles:
+ active: @env@
+ mvc:
+ throw-exception-if-no-handler-found: true
+ jackson:
+ date-format: yyyy-MM-dd HH:mm:ss
+ time-zone: Asia/Hong_Kong
+ cloud:
+ consul:
+ discovery:
+ register: true
+ instance-id: ${spring.application.name}-${spring.cloud.client.hostname}-${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
+ service-name: ${spring.application.name}
+ port: ${server.port}
+ prefer-ip-address: true
+ ip-address: ${spring.cloud.client.ip-address}
+ health-check-critical-timeout: 15s
+ gateway:
+ discovery:
+ locator:
+ enabled: true
+ lower-case-service-id: true
+ # https://cloud.spring.io/spring-cloud-gateway/multi/multi__cors_configuration.html
+ globalcors:
+ corsConfigurations:
+ '[/**]':
+ allowedOrigins: "*"
+ allowedMethods: "*"
+ redis:
+ database: 0
+ timeout: 10000ms
+ client-type: LETTUCE
+ lettuce:
+ pool:
+ max-active: 20
+ max-idle: 10
+ max-wait: -1ms
+ min-idle: 0
+
+management:
+ endpoints:
+ web:
+ exposure:
+ include: "*"
+ endpoint:
+ health:
+ show-details: ALWAYS
+
+logging:
+ config: classpath:logback-configuration/logback-${spring.profiles.active}.xml
+
+maf:
+ project-property:
+ base-package: @project.groupId@
+ context-path: ${server.servlet.context-path}
+ group-id: @project.groupId@
+ project-parent-artifact-id: @project.parent.artifactId@
+ project-artifact-id: @project.artifactId@
+ version: @project.version@
+ description: @project.description@
+ jdk-version: @java.version@
+ environment: ${spring.profiles.active}
+ url: @project.url@
+ inception-year: @inceptionYear@
+ organization-name: @project.organization.name@
+ organization-url: @project.organization.url@
+ issue-management-system: @project.issueManagement.system@
+ issue-management-url: @project.issueManagement.url@
+ developer-name: @developerName@
+ developer-email: @developerEmail@
+ developer-url: @developerUrl@
+ configuration:
+ ignored-url:
+ post:
+ - "/auth-center/users/signup"
+ - "/auth-center/users/login"
+ - "/auth-center/users/logout"
+ get:
+ - "/favicon.ico"
+ pattern:
+ - "/static/**"
+ - "/*/static/**"
+ - "/actuator/**"
+ - "/*/druid/**"
+ - "/swagger-resources/**"
+ - "/v2/api-docs/**"
+ - "/*/v2/api-docs/**"
+ - "/*/webjars/**"
+ - "/doc.html"
+ - "/oss-center/**"
diff --git a/exercise-mis/src/main/resources/banner.txt b/api-gateway/src/main/resources/banner.txt
similarity index 64%
rename from exercise-mis/src/main/resources/banner.txt
rename to api-gateway/src/main/resources/banner.txt
index 81dc78b5..484a2316 100644
--- a/exercise-mis/src/main/resources/banner.txt
+++ b/api-gateway/src/main/resources/banner.txt
@@ -1,12 +1,13 @@
${AnsiStyle.BOLD}${AnsiColor.BRIGHT_GREEN}
- ______ _ __ ____________
- / ____/ _____ __________(_)_______ / |/ / _/ ___/
- / __/ | |/_/ _ \/ ___/ ___/ / ___/ _ \ / /|_/ // / \__ \
- / /____> __/ / / /__/ (__ ) __/ / / / // / ___/ /
-/_____/_/|_|\___/_/ \___/_/____/\___/ /_/ /_/___//____/
-${AnsiStyle.BOLD}Exercise MIS :: Powered by Spring Boot ::${spring-boot.formatted-version}
-${AnsiColor.CYAN}Author: Johnny Miller (鍾俊), email: johnnysviva@outlook.com
-${AnsiStyle.NORMAL}${AnsiColor.MAGENTA}http://patorjk.com/software/taag/#p=display&f=Slant&t=Exercise%20MIS
+ ___ ____ ____ ______ __
+ / | / __ \/ _/ / ____/___ _/ /____ _ ______ ___ __
+ / /| | / /_/ // / / / __/ __ `/ __/ _ \ | /| / / __ `/ / / /
+ / ___ |/ ____// / / /_/ / /_/ / /_/ __/ |/ |/ / /_/ / /_/ /
+/_/ |_/_/ /___/ \____/\__,_/\__/\___/|__/|__/\__,_/\__, /
+ /____/
+${AnsiStyle.BOLD}API Gateway :: Powered by Spring Boot ::${spring-boot.formatted-version}
+${AnsiColor.CYAN}Author: Johnny Miller (锺俊), email: johnnysviva@outlook.com
+${AnsiStyle.NORMAL}${AnsiColor.MAGENTA}http://patorjk.com/software/taag/#p=display&f=Slant&t=API%20Gateway
${AnsiColor.BRIGHT_BLACK}
-------------------------------------------Font Info-------------------------------------------
Slant by Glenn Chappell 3/93 -- based on Standard
diff --git a/api-gateway/src/main/resources/bootstrap.yml b/api-gateway/src/main/resources/bootstrap.yml
new file mode 100644
index 00000000..79e3552f
--- /dev/null
+++ b/api-gateway/src/main/resources/bootstrap.yml
@@ -0,0 +1,18 @@
+spring:
+ application:
+ name: @project.artifactId@
+ cloud:
+ consul:
+ host: "should-be-passed-by-java-opts"
+ port: 8500
+ config:
+ enabled: true
+ prefix: config
+ # `default-context` should be equal to Spring application name
+ default-context: @project.artifactId@
+ profile-separator: "::"
+ format: YAML
+ data-key: "data"
+ watch:
+ enabled: true
+ delay: 1000
diff --git a/api-portal/src/main/resources/configuration/logback/logback-base.xml b/api-gateway/src/main/resources/logback-configuration/logback-base.xml
similarity index 69%
rename from api-portal/src/main/resources/configuration/logback/logback-base.xml
rename to api-gateway/src/main/resources/logback-configuration/logback-base.xml
index 86d8546d..1629f54f 100644
--- a/api-portal/src/main/resources/configuration/logback/logback-base.xml
+++ b/api-gateway/src/main/resources/logback-configuration/logback-base.xml
@@ -10,7 +10,7 @@
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
-
+
-
+
+
-
+
+
-
+
+
-
+
+
-
+
+
@@ -60,11 +65,19 @@
- ${LOG_HOME}/${PROJECT_ARTIFACT_Id}${LOG_FILE_SUFFIX}.%d{yyyy-MM-dd}.%i.log.gz
+ ${LOG_HOME}/${APPLICATION}-${ENVIRONMENT}-${HOSTNAME}.%d{yyyy-MM-dd}.%i.log.gz
5MB
7
1GB
+
+
+
+ ${LOGSTASH_HOST}:4560
+
+ {"applicationName": "${APPLICATION}", "environment": "${ENVIRONMENT}"}
+
+
diff --git a/auth-center/src/main/resources/configuration/logback/logback-development-docker.xml b/api-gateway/src/main/resources/logback-configuration/logback-development-docker.xml
similarity index 68%
rename from auth-center/src/main/resources/configuration/logback/logback-development-docker.xml
rename to api-gateway/src/main/resources/logback-configuration/logback-development-docker.xml
index f38e6c2d..86b71ee2 100644
--- a/auth-center/src/main/resources/configuration/logback/logback-development-docker.xml
+++ b/api-gateway/src/main/resources/logback-configuration/logback-development-docker.xml
@@ -1,10 +1,11 @@
-
+
+
diff --git a/auth-center/src/main/resources/configuration/logback/logback-development-local.xml b/api-gateway/src/main/resources/logback-configuration/logback-development-local.xml
similarity index 68%
rename from auth-center/src/main/resources/configuration/logback/logback-development-local.xml
rename to api-gateway/src/main/resources/logback-configuration/logback-development-local.xml
index f38e6c2d..86b71ee2 100644
--- a/auth-center/src/main/resources/configuration/logback/logback-development-local.xml
+++ b/api-gateway/src/main/resources/logback-configuration/logback-development-local.xml
@@ -1,10 +1,11 @@
-
+
+
diff --git a/auth-center/src/main/resources/configuration/logback/logback-production.xml b/api-gateway/src/main/resources/logback-configuration/logback-production.xml
similarity index 68%
rename from auth-center/src/main/resources/configuration/logback/logback-production.xml
rename to api-gateway/src/main/resources/logback-configuration/logback-production.xml
index f38e6c2d..86b71ee2 100644
--- a/auth-center/src/main/resources/configuration/logback/logback-production.xml
+++ b/api-gateway/src/main/resources/logback-configuration/logback-production.xml
@@ -1,10 +1,11 @@
-
+
+
diff --git a/api-portal/src/main/resources/configuration/logback/logback-stage.xml b/api-gateway/src/main/resources/logback-configuration/logback-stage.xml
similarity index 68%
rename from api-portal/src/main/resources/configuration/logback/logback-stage.xml
rename to api-gateway/src/main/resources/logback-configuration/logback-stage.xml
index f38e6c2d..86b71ee2 100644
--- a/api-portal/src/main/resources/configuration/logback/logback-stage.xml
+++ b/api-gateway/src/main/resources/logback-configuration/logback-stage.xml
@@ -1,10 +1,11 @@
-
+
+
diff --git a/api-portal/src/main/resources/configuration/logback/logback-test.xml b/api-gateway/src/main/resources/logback-configuration/logback-test.xml
similarity index 66%
rename from api-portal/src/main/resources/configuration/logback/logback-test.xml
rename to api-gateway/src/main/resources/logback-configuration/logback-test.xml
index f1916a0f..3c705245 100644
--- a/api-portal/src/main/resources/configuration/logback/logback-test.xml
+++ b/api-gateway/src/main/resources/logback-configuration/logback-test.xml
@@ -1,10 +1,11 @@
-
+
+
diff --git a/gateway/src/test/java/com/jmsoftware/maf/gateway/GatewayApplicationTests.java b/api-gateway/src/test/java/com/jmsoftware/maf/apigateway/ApiGatewayApplicationTests.java
similarity index 68%
rename from gateway/src/test/java/com/jmsoftware/maf/gateway/GatewayApplicationTests.java
rename to api-gateway/src/test/java/com/jmsoftware/maf/apigateway/ApiGatewayApplicationTests.java
index 15696948..2ffb2727 100644
--- a/gateway/src/test/java/com/jmsoftware/maf/gateway/GatewayApplicationTests.java
+++ b/api-gateway/src/test/java/com/jmsoftware/maf/apigateway/ApiGatewayApplicationTests.java
@@ -1,10 +1,10 @@
-package com.jmsoftware.maf.gateway;
+package com.jmsoftware.maf.apigateway;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
-class GatewayApplicationTests {
+class ApiGatewayApplicationTests {
@Test
void contextLoads() {
diff --git a/api-gateway/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.java b/api-gateway/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.java
new file mode 100644
index 00000000..397289d9
--- /dev/null
+++ b/api-gateway/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.java
@@ -0,0 +1,25 @@
+package com.jmsoftware.maf.apigateway;
+
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.util.AntPathMatcher;
+
+/**
+ * Description: AuthorizationTests, change description here.
+ *
+ * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 1/13/2021 11:27 AM
+ **/
+@Slf4j
+@SpringBootTest
+public class AuthorizationTests {
+ @Test
+ void antPathMatcherTests() {
+ val antPathMatcher = new AntPathMatcher();
+ val urlMatched = antPathMatcher.match("/**", "/spring-boot-admin/common/app-info");
+ log.info("urlMatched: {}", urlMatched);
+ Assertions.assertTrue(urlMatched);
+ }
+}
diff --git a/api-portal/pom.xml b/api-portal/pom.xml
deleted file mode 100644
index 5e555f39..00000000
--- a/api-portal/pom.xml
+++ /dev/null
@@ -1,165 +0,0 @@
-
-
- 4.0.0
-
-
- api-portal
- Muscle and Fitness Server :: API Portal
- API Portal is an entrance for upcoming requests from any external devices. Responsible for aggregating
- internal microservices and exposing to external.
-
-
- com.jmsoftware.maf
- muscle-and-fitness-server
- 0.0.1
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
- com.google.cloud.tools
- jib-maven-plugin
- 2.2.0
-
-
-
- buildDockerImagePhase
- verify
-
- dockerBuild
-
-
-
-
- buildAndPushDockerImagePhase
- install
-
- build
-
-
-
-
-
-
- openjdk:11.0.9.1-jre-slim
-
-
- docker.io/ijohnnymiller/${project.parent.artifactId}.${project.artifactId}
-
- ${project.version}
-
-
-
-
- /${project.artifactId}
-
- -Dfile.encoding=${project.build.sourceEncoding}
-
-
- ${api-portal.port}
-
- USE_CURRENT_TIMESTAMP
-
-
-
-
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.springframework.cloud
- spring-cloud-starter-netflix-eureka-client
-
-
- de.codecentric
- spring-boot-admin-starter-client
- ${spring-boot-admin.version}
-
-
- org.springframework.cloud
- spring-cloud-starter-zipkin
-
-
- org.springframework.boot
- spring-boot-starter-security
-
-
- org.springframework.boot
- spring-boot-starter-data-redis
-
-
- org.springframework.integration
- spring-integration-sftp
-
-
-
- com.jmsoftware.maf
- common
-
-
- com.jmsoftware.maf
- muscle-and-fitness-server-spring-boot-starter
-
-
-
- org.springframework.security
- spring-security-test
- test
-
-
-
-
- com.baomidou
- mybatis-plus-boot-starter
- 3.3.1
-
-
- mysql
- mysql-connector-java
- runtime
-
-
- com.alibaba
- druid
- 1.1.22
-
-
-
- redis.clients
- jedis
-
-
-
-
- io.jsonwebtoken
- jjwt-api
- 0.11.1
-
-
- io.jsonwebtoken
- jjwt-impl
- 0.11.1
- runtime
-
-
- io.jsonwebtoken
- jjwt-jackson
- 0.11.1
- runtime
-
-
-
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/ApiPortalApplication.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/ApiPortalApplication.java
deleted file mode 100644
index 2a3cb9e3..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/ApiPortalApplication.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.jmsoftware.maf.apiportal;
-
-import com.jmsoftware.maf.apiportal.universal.configuration.ProjectProperty;
-import com.jmsoftware.maf.muscleandfitnessserverspringbootstarter.helper.IpHelper;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.cloud.openfeign.EnableFeignClients;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.TimeZone;
-
-/**
- * ApiPortalApplication
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
- * @date 3/14/20 1:58 PM
- **/
-@Slf4j
-@EnableFeignClients
-@EnableDiscoveryClient
-@SpringBootApplication
-public class ApiPortalApplication {
- private static final String LINE_SEPARATOR = System.lineSeparator();
- private static ProjectProperty projectProperty;
- private static IpHelper ipHelper;
-
- public ApiPortalApplication(ProjectProperty projectProperty, IpHelper ipHelper) {
- ApiPortalApplication.projectProperty = projectProperty;
- ApiPortalApplication.ipHelper = ipHelper;
- }
-
- public static void main(String[] args) {
- val startInstant = Instant.now();
- SpringApplication.run(ApiPortalApplication.class, args);
- val endInstant = Instant.now();
- val duration = Duration.between(startInstant, endInstant);
- log.info("🥳 Congratulations! 🎉");
- log.info("🖥 {}@{} started!", projectProperty.getProjectArtifactId(), projectProperty.getVersion());
- log.info("⚙️ Environment: {}", projectProperty.getEnvironment());
- log.info("⏳ Deployment duration: {} seconds ({} ms)", duration.getSeconds(), duration.toMillis());
- log.info("⏰ App started at {} (timezone - {})", endInstant, TimeZone.getDefault().getDisplayName());
- log.info("{} App running at{} - Local: http://localhost:{}{}/{} - Network: {}/{}",
- LINE_SEPARATOR, LINE_SEPARATOR, ipHelper.getServerPort(), projectProperty.getContextPath(),
- LINE_SEPARATOR, ipHelper.getPublicIp(),projectProperty.getContextPath());
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/controller/AuthenticationController.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/controller/AuthenticationController.java
deleted file mode 100644
index b8230877..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/controller/AuthenticationController.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.jmsoftware.maf.apiportal.auth.controller;
-
-import com.jmsoftware.maf.apiportal.auth.entity.LoginPayload;
-import com.jmsoftware.maf.apiportal.auth.entity.LoginResponse;
-import com.jmsoftware.maf.apiportal.auth.entity.RegisterPayload;
-import com.jmsoftware.maf.apiportal.auth.service.AuthenticationService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.validation.Valid;
-
-/**
- *
AuthenticationController
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/8/20 11:06 AM
- **/
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/authentication")
-@Api(tags = {"Authentication Controller"})
-public class AuthenticationController {
- private final AuthenticationService authenticationService;
-
- @PostMapping("/register")
- @ApiOperation(value = "/register", notes = "Register (create an account)")
- public ResponseBodyBean register(@Valid @RequestBody RegisterPayload payload) {
- return ResponseBodyBean.ofSuccess(authenticationService.register(payload));
- }
-
- @PostMapping("/login")
- @ApiOperation(value = "/login", notes = "Login")
- public ResponseBodyBean login(@Valid @RequestBody LoginPayload payload) {
- return ResponseBodyBean.ofSuccess(authenticationService.login(payload));
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/entity/LoginResponse.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/entity/LoginResponse.java
deleted file mode 100644
index 61b46cbe..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/entity/LoginResponse.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.jmsoftware.maf.apiportal.auth.entity;
-
-import lombok.Data;
-
-/**
- * LoginResponse
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/8/20 2:07 PM
- **/
-@Data
-public class LoginResponse {
- private String jwt;
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/entity/RegisterPayload.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/entity/RegisterPayload.java
deleted file mode 100644
index 7b92447d..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/entity/RegisterPayload.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.jmsoftware.maf.apiportal.auth.entity;
-
-import lombok.Data;
-import org.hibernate.validator.constraints.Length;
-
-import javax.validation.constraints.NotEmpty;
-
-/**
- *
RegisterPayload
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/9/20 3:53 PM
- **/
-@Data
-public class RegisterPayload {
- /**
- * Username (Unique)
- */
- @NotEmpty
- @Length(min = 4, max = 50)
- private String username;
- /**
- * Email (Unique)
- */
- @NotEmpty
- @Length(max = 100)
- private String email;
- /**
- * Password
- */
- @NotEmpty
- @Length(min = 8, max = 30)
- private String password;
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/service/AuthenticationService.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/service/AuthenticationService.java
deleted file mode 100644
index 0d37b726..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/service/AuthenticationService.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.jmsoftware.maf.apiportal.auth.service;
-
-import com.jmsoftware.maf.apiportal.auth.entity.LoginPayload;
-import com.jmsoftware.maf.apiportal.auth.entity.LoginResponse;
-import com.jmsoftware.maf.apiportal.auth.entity.RegisterPayload;
-
-/**
- *
AuthenticationService
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/8/20 2:04 PM
- */
-public interface AuthenticationService {
- /**
- * Register.
- *
- * @param payload the payload
- * @return the long
- */
- Long register(RegisterPayload payload);
-
- /**
- * Login login response.
- *
- * @param payload the payload
- * @return the login response
- */
- LoginResponse login(LoginPayload payload);
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/service/impl/AuthenticationServiceImpl.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/service/impl/AuthenticationServiceImpl.java
deleted file mode 100644
index ab3c1fa9..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/auth/service/impl/AuthenticationServiceImpl.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.jmsoftware.maf.apiportal.auth.service.impl;
-
-import com.jmsoftware.maf.apiportal.auth.entity.LoginPayload;
-import com.jmsoftware.maf.apiportal.auth.entity.LoginResponse;
-import com.jmsoftware.maf.apiportal.auth.entity.RegisterPayload;
-import com.jmsoftware.maf.apiportal.auth.service.AuthenticationService;
-import com.jmsoftware.maf.apiportal.remoteapi.AuthCenterRemoteApi;
-import com.jmsoftware.maf.apiportal.universal.service.JwtService;
-import com.jmsoftware.maf.common.domain.authcenter.user.SaveUserForRegisteringPayload;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.stereotype.Service;
-
-/**
- *
AuthenticationServiceImpl
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/8/20 2:04 PM
- **/
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class AuthenticationServiceImpl implements AuthenticationService {
- private final BCryptPasswordEncoder encoder;
- private final AuthenticationManager authenticationManager;
- private final JwtService jwtService;
- private final AuthCenterRemoteApi authCenterRemoteApi;
-
- @Override
- public Long register(RegisterPayload payload) {
- val saveUserForRegisteringPayload = new SaveUserForRegisteringPayload();
- saveUserForRegisteringPayload.setUsername(payload.getUsername());
- saveUserForRegisteringPayload.setEmail(payload.getEmail());
- saveUserForRegisteringPayload.setEncodedPassword(encoder.encode(payload.getPassword()));
- val response = authCenterRemoteApi.saveUserForRegistering(saveUserForRegisteringPayload);
- log.info("Registered an new user account. User ID: {}", response.getData().getUserId());
- return response.getData().getUserId();
- }
-
- @Override
- @SneakyThrows
- public LoginResponse login(LoginPayload payload) {
- val authenticationToken = new UsernamePasswordAuthenticationToken(payload.getLoginToken(),
- payload.getPassword());
- val authentication = authenticationManager.authenticate(authenticationToken);
- SecurityContextHolder.getContext().setAuthentication(authentication);
- val jwt = jwtService.createJwt(authentication, payload.getRememberMe());
- val loginResponse = new LoginResponse();
- loginResponse.setJwt(jwt);
- return loginResponse;
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/remoteapi/AuthCenterRemoteApi.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/remoteapi/AuthCenterRemoteApi.java
deleted file mode 100644
index 407edc12..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/remoteapi/AuthCenterRemoteApi.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.jmsoftware.maf.apiportal.remoteapi;
-
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdResponse;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdPayload;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse;
-import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenPayload;
-import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse;
-import com.jmsoftware.maf.common.domain.authcenter.user.SaveUserForRegisteringPayload;
-import com.jmsoftware.maf.common.domain.authcenter.user.SaveUserForRegisteringResponse;
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-
-import javax.validation.Valid;
-
-/**
- *
AuthCenterRemoteApi
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/10/20 4:50 PM
- */
-@Validated
-@FeignClient(name = "auth-center")
-public interface AuthCenterRemoteApi {
- /**
- * Gets user by login token.
- *
- * @param payload the payload
- * @return the user by login token
- */
- @PostMapping("/user-remote-api/get-user-by-login-token")
- ResponseBodyBean getUserByLoginToken(@Valid @RequestBody GetUserByLoginTokenPayload payload);
-
- /**
- * Gets role list by user id.
- *
- * @param payload the payload
- * @return the role list by user id
- */
- @PostMapping("/role-remote-api/get-role-list-by-user-id")
- ResponseBodyBean getRoleListByUserId(@Valid @RequestBody GetRoleListByUserIdPayload payload);
-
- /**
- * Save user for registering response body bean.
- *
- * @param payload the payload
- * @return the response body bean
- */
- @PostMapping("/user-remote-api/save-user-for-registering")
- ResponseBodyBean saveUserForRegistering(@Valid @RequestBody SaveUserForRegisteringPayload payload);
-
- /**
- * Gets permission list by role id list.
- *
- * @param payload the payload
- * @return the permission list by role id list
- */
- @PostMapping("/permission-remote-api/get-permission-list-by-role-id-list")
- ResponseBodyBean getPermissionListByRoleIdList(@Valid @RequestBody GetPermissionListByRoleIdListPayload payload);
-
- /**
- * Get permission list by user id response body bean.
- *
- * @param payload the payload
- * @return the response body bean
- */
- @PostMapping("/permission-remote-api/get-permission-list-by-user-id")
- ResponseBodyBean getPermissionListByUserId(@Valid @RequestBody GetPermissionListByUserIdPayload payload);
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/Constants.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/Constants.java
deleted file mode 100644
index 3e73e83b..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/Constants.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-/**
- * Constants
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Slf4j
-@Component
-public class Constants {
- public Constants(ProjectProperty projectProperty) {
- REDIS_JWT_KEY_PREFIX = String.format("%s:jwt:", projectProperty.getProjectParentArtifactId());
- log.info("Initiated 'REDIS_JWT_KEY_PREFIX': {}", REDIS_JWT_KEY_PREFIX);
- }
-
- /**
- * Key prefix of JWT stored in Redis.
- */
- public static String REDIS_JWT_KEY_PREFIX;
- /**
- * Token key of request header.
- */
- public static final String REQUEST_TOKEN_KEY = "Authorization";
- /**
- * Prefix of JWT.
- */
- public static final String JWT_PREFIX = "Bearer ";
- /**
- * Star sign
- */
- public static final String ASTERISK = "*";
- /**
- * At sign
- */
- public static final String AT_SIGN = "@";
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/CustomConfiguration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/CustomConfiguration.java
deleted file mode 100644
index c189a948..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/CustomConfiguration.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
-
-/**
- *
CustomConfiguration
- * Custom configurations which are written in .yml files, containing a variety of fragmentary configs. Such as,
- * Druid login info, web security switch, web log and so on.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-23 14:24
- **/
-@Data
-@Component
-@ConfigurationProperties(prefix = "custom.configuration")
-public class CustomConfiguration {
- /**
- * The username of super user who has no restriction to access any system's resources.
- * ATTENTION : The value of username of super user must be equal to the value that is
- * persistent in database.
- */
- private String superUser;
- /**
- * Ignore URLs
- */
- private IgnoredRequest ignoredRequest;
- private String druidLoginName;
- private String druidPassword;
- /**
- * Web security feature switch. Default is false.
- * true - disable web security; false - enable web security.
- */
- private Boolean webSecurityDisabled = false;
- /**
- * Web request log switch. Default is false.
- *
- * true - disable web request log; false - enable web request log.
- */
- private Boolean webRequestLogDisabled = false;
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/DruidConfiguration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/DruidConfiguration.java
deleted file mode 100644
index a5a2a166..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/DruidConfiguration.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import com.alibaba.druid.pool.DruidDataSource;
-import com.alibaba.druid.support.http.StatViewServlet;
-import com.alibaba.druid.support.http.WebStatFilter;
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.boot.web.servlet.ServletRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import javax.sql.DataSource;
-
-/**
- *
DruidConfiguration
- *
- * Druid Configuration
- * Click me to view Druid Monitor
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-24 13:31
- **/
-@Configuration
-@RequiredArgsConstructor
-public class DruidConfiguration {
- @Bean
- public ServletRegistrationBean druidServlet() {
- val servletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
- servletRegistrationBean.addInitParameter("loginUsername", "admin");
- servletRegistrationBean.addInitParameter("loginPassword", "admin");
- servletRegistrationBean.addInitParameter("resetEnable", "false");
- return servletRegistrationBean;
- }
-
- @Bean
- public FilterRegistrationBean filterRegistrationBean() {
- val filterRegistrationBean = new FilterRegistrationBean();
- filterRegistrationBean.setFilter(new WebStatFilter());
- filterRegistrationBean.addUrlPatterns("/*");
- // Ignored resources
- filterRegistrationBean.addInitParameter("exclusions",
- "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
- filterRegistrationBean.addInitParameter("profileEnable", "true");
- filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
- filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
- return filterRegistrationBean;
- }
-
- @Bean
- @ConfigurationProperties(prefix = "spring.datasource")
- public DataSource druidDataSource() {
- return new DruidDataSource();
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/IgnoredRequest.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/IgnoredRequest.java
deleted file mode 100644
index 9e030140..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/IgnoredRequest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import com.google.common.collect.Lists;
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * IgnoredRequest
- *
- * Ignored request configuration.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Data
-public class IgnoredRequest {
- /**
- * Ignored URL pattern.
- */
- private List pattern = Lists.newArrayList();
- /**
- * Ignored GET request.
- */
- private List get = Lists.newArrayList();
- /**
- * Ignored POST request.
- */
- private List post = Lists.newArrayList();
- /**
- * Ignored DELETE request.
- */
- private List delete = Lists.newArrayList();
- /**
- * Ignored PUT request.
- */
- private List put = Lists.newArrayList();
- /**
- * Ignored HEAD request.
- */
- private List head = Lists.newArrayList();
- /**
- * Ignored PATCH request.
- */
- private List patch = Lists.newArrayList();
- /**
- * Ignored OPTIONS request.
- */
- private List options = Lists.newArrayList();
- /**
- * Ignored TRACE request.
- */
- private List trace = Lists.newArrayList();
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/JwtConfiguration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/JwtConfiguration.java
deleted file mode 100644
index edd4f961..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/JwtConfiguration.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import lombok.Data;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
-
-import java.nio.charset.StandardCharsets;
-
-/**
- * JwtConfiguration
- *
- * Ignored request configuration.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Data
-@Slf4j
-@Component
-@ConfigurationProperties(prefix = "jwt.configuration")
-public class JwtConfiguration {
- public JwtConfiguration(ProjectProperty projectProperty) {
- this.signingKey = String.format("%s %s", projectProperty.getProjectParentArtifactId(), projectProperty.getVersion());
- log.info("Initiated JWT signing key: {}. The specified key byte array is {} bits", this.signingKey,
- this.signingKey.getBytes(StandardCharsets.UTF_8).length * 8);
- }
-
- /**
- * JWT signing key, which is equal to the string value of group id of project.
- */
- private String signingKey;
- /**
- * Time to live of JWT. Default: 3 * 600000 milliseconds (30 min).
- */
- private Long ttl = 3 * 600000L;
- /**
- * Time to live of JWT for remember me, Default: 7 * 86400000 milliseconds (7 day)
- */
- private Long ttlForRememberMe = 7 * 86400000L;
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/MyBatisPlusConfiguration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/MyBatisPlusConfiguration.java
deleted file mode 100644
index 1b5cca54..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/MyBatisPlusConfiguration.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
-import lombok.val;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.transaction.annotation.EnableTransactionManagement;
-
-/**
- *
MyBatisPlusConfiguration
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-05-02 11:57
- **/
-@Configuration
-@EnableTransactionManagement
-public class MyBatisPlusConfiguration {
- /**
- * Inject bean to enable pagination.
- *
- * @return bean for pagination
- */
- @Bean
- public PaginationInterceptor paginationInterceptor() {
- val paginationInterceptor = new PaginationInterceptor();
- // Set maximum query record count
- paginationInterceptor.setLimit(100L);
- // Enable JSQL Parser Count Optimizing (for left join)
- paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
- return paginationInterceptor;
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/ProjectProperty.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/ProjectProperty.java
deleted file mode 100644
index 669f177d..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/ProjectProperty.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
-
-/**
- *
ProjectProperty
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-04-18 13:01
- **/
-@Data
-@Component
-@ConfigurationProperties(prefix = "project.property")
-public class ProjectProperty {
- private String basePackage;
- private String contextPath;
- private String groupId;
- private String projectParentArtifactId;
- private String projectArtifactId;
- private String version;
- private String description;
- private String jdkVersion;
- private String environment;
- private String url;
- private String inceptionYear;
- private String organizationName;
- private String organizationUrl;
- private String issueManagementSystem;
- private String issueManagementUrl;
- private String developerName;
- private String developerEmail;
- private String developerUrl;
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/RedisClientConfiguration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/RedisClientConfiguration.java
deleted file mode 100644
index 04f9037d..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/RedisClientConfiguration.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import lombok.val;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
-import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
-import org.springframework.cache.annotation.CachingConfigurerSupport;
-import org.springframework.cache.annotation.EnableCaching;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
-import org.springframework.data.redis.serializer.StringRedisSerializer;
-
-import java.io.Serializable;
-
-/**
- *
RedisClientConfiguration
- *
- * Ignored request configuration.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Configuration
-@EnableCaching
-@AutoConfigureAfter(RedisAutoConfiguration.class)
-public class RedisClientConfiguration extends CachingConfigurerSupport {
- /**
- * Redis template. Support for <String, Serializable>
- */
- @Bean
- public RedisTemplate redisFactory(LettuceConnectionFactory lettuceConnectionFactory) {
- val template = new RedisTemplate();
- template.setKeySerializer(new StringRedisSerializer());
- template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
- template.setConnectionFactory(lettuceConnectionFactory);
- return template;
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SecurityHandlerConfiguration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SecurityHandlerConfiguration.java
deleted file mode 100644
index 4971d1c1..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SecurityHandlerConfiguration.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import com.jmsoftware.maf.common.constant.HttpStatus;
-import com.jmsoftware.maf.muscleandfitnessserverspringbootstarter.util.ResponseUtil;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.access.AccessDeniedHandler;
-
-/**
- * SecurityHandlerConfiguration
- *
- * Security handler configuration.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Slf4j
-@Configuration
-public class SecurityHandlerConfiguration {
- @Bean
- public AuthenticationEntryPoint authenticationEntryPoint() {
- return ((request, response, authException) -> {
- val formattedMessage = String.format("Authentication encountered an exception! Exception message: %s",
- authException.getMessage());
- log.error(formattedMessage);
- ResponseUtil.renderJson(response, HttpStatus.FORBIDDEN, formattedMessage);
- });
- }
-
- @Bean
- public AccessDeniedHandler accessDeniedHandler() {
- return ((request, response, accessDeniedException) -> {
- val formattedMessage = String.format("Access was denied! Exception message: %s",
- accessDeniedException.getMessage());
- log.error(formattedMessage);
- ResponseUtil.renderJson(response, HttpStatus.FORBIDDEN, formattedMessage);
- });
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SftpClientConfiguration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SftpClientConfiguration.java
deleted file mode 100644
index 8a07b4bf..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SftpClientConfiguration.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import com.jcraft.jsch.ChannelSftp;
-import lombok.Data;
-import lombok.val;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.core.io.Resource;
-import org.springframework.expression.common.LiteralExpression;
-import org.springframework.integration.annotation.ServiceActivator;
-import org.springframework.integration.file.remote.session.CachingSessionFactory;
-import org.springframework.integration.file.remote.session.SessionFactory;
-import org.springframework.integration.sftp.outbound.SftpMessageHandler;
-import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
-import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
-import org.springframework.messaging.MessageHandler;
-import org.springframework.stereotype.Component;
-
-import java.io.File;
-
-/**
- *
SftpClientConfiguration
- * SFTP client configuration
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-04 18:18
- **/
-@Data
-@Component
-@ConfigurationProperties(prefix = "sftp.client.configuration")
-public class SftpClientConfiguration {
- /**
- * SFTP server IP
- */
- private String host;
- /**
- * SFTP server port
- */
- private Integer port;
- /**
- * Login user
- */
- private String user;
- /**
- * Login password
- */
- private String password;
- /**
- * Remote directory
- */
- private String directory;
- /**
- * Private key
- */
- private Resource privateKey;
- /**
- * Private key pass phrase
- */
- private String privateKeyPassPhrase;
- /**
- * The maximum cache size of session. Default: 10
- */
- private Integer sessionCacheSize = 10;
- /**
- * The session wait timeout (time unit: MILLISECONDS). Default: 10 * 1000L (10 seconds)
- */
- private Long sessionWaitTimeout = 10 * 1000L;
-
- @Bean
- public SessionFactory sftpSessionFactory() {
- val factory = new DefaultSftpSessionFactory(true);
- factory.setHost(host);
- factory.setPort(port);
- factory.setUser(user);
- if (privateKey != null) {
- factory.setPrivateKey(privateKey);
- factory.setPrivateKeyPassphrase(privateKeyPassPhrase);
- } else {
- factory.setPassword(password);
- }
- factory.setAllowUnknownKeys(true);
- // We return a caching session factory, so that we don't have to reconnect to SFTP server for each time
- val cachingSessionFactory = new CachingSessionFactory<>(factory, sessionCacheSize);
- cachingSessionFactory.setSessionWaitTimeout(sessionWaitTimeout);
- return cachingSessionFactory;
- }
-
- @Bean
- @ServiceActivator(inputChannel = "toSftpChannel")
- @SuppressWarnings("UnresolvedMessageChannel")
- public MessageHandler handler(SessionFactory sftpSessionFactory) {
- val handler = new SftpMessageHandler(sftpSessionFactory);
- handler.setRemoteDirectoryExpression(new LiteralExpression(directory));
- handler.setFileNameGenerator(message -> {
- if (message.getPayload() instanceof File) {
- return ((File) message.getPayload()).getName();
- } else {
- throw new IllegalArgumentException("File expected as payload.");
- }
- });
- return handler;
- }
-
- @Bean
- public SftpRemoteFileTemplate template(SessionFactory sftpSessionFactory) {
- return new SftpRemoteFileTemplate(sftpSessionFactory);
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SftpUploadGateway.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SftpUploadGateway.java
deleted file mode 100644
index 8ad0a46d..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/SftpUploadGateway.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import org.springframework.integration.annotation.Gateway;
-import org.springframework.integration.annotation.MessagingGateway;
-import org.springframework.stereotype.Component;
-
-import java.io.File;
-
-/**
- * SftpUploadGateway
- * Change description here
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-04 21:03
- **/
-@Component
-@MessagingGateway
-public interface SftpUploadGateway {
- /**
- * Upload file
- *
- * @param file file
- */
- @Gateway(requestChannel = "toSftpChannel")
- @SuppressWarnings("UnresolvedMessageChannel")
- void upload(File file);
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/Swagger2Configuration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/Swagger2Configuration.java
deleted file mode 100644
index b1bded5d..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/Swagger2Configuration.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import springfox.documentation.builders.ApiInfoBuilder;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.service.ApiInfo;
-import springfox.documentation.service.Contact;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spring.web.plugins.Docket;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
-
-/**
- * Swagger2Configuration
- *
- * Swagger 2 Configuration
- * Click me to view
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-02-07 16:15
- **/
-@Configuration
-@EnableSwagger2
-@RequiredArgsConstructor
-public class Swagger2Configuration {
- private final ProjectProperty projectProperty;
- private static final String LINE_SEPARATOR = System.lineSeparator();
-
- @Bean
- public Docket createRestApi() {
- return new Docket(DocumentationType.SWAGGER_2)
- .apiInfo(apiInfo())
- .select()
- .apis(RequestHandlerSelectors.basePackage(projectProperty.getBasePackage()))
- .paths(PathSelectors.any())
- .build();
- }
-
- private ApiInfo apiInfo() {
- val projectArtifactId = projectProperty.getProjectArtifactId();
- val version = projectProperty.getVersion();
- val developerEmail = projectProperty.getDeveloperEmail();
- val developerUrl = projectProperty.getDeveloperUrl();
- return new ApiInfoBuilder()
- .title(String.format("API for %s@%s", projectArtifactId, version))
- .description(String.format("%s %sArtifact ID: %s%sEnvironment: %s",
- projectProperty.getDescription(),
- LINE_SEPARATOR,
- projectArtifactId,
- LINE_SEPARATOR,
- projectProperty.getEnvironment()))
- .contact(new Contact(String.format("%s, email: %s%sHome page: %s",
- projectProperty.getDeveloperName(),
- developerEmail,
- LINE_SEPARATOR,
- developerUrl),
- developerUrl, developerEmail))
- .version(version)
- .build();
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/WebSecurityConfiguration.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/WebSecurityConfiguration.java
deleted file mode 100644
index de1cc2c4..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/configuration/WebSecurityConfiguration.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.configuration;
-
-import com.jmsoftware.maf.apiportal.universal.filter.JwtAuthenticationFilter;
-import com.jmsoftware.maf.apiportal.universal.service.impl.CustomUserDetailsServiceImpl;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-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.config.annotation.authentication.builders.AuthenticationManagerBuilder;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.access.AccessDeniedHandler;
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-
-import java.util.Optional;
-
-/**
- *
WebSecurityConfiguration
- *
- * Security handler configuration.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Slf4j
-@Configuration
-@EnableWebSecurity
-@RequiredArgsConstructor
-public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
- private final CustomConfiguration customConfiguration;
- private final AccessDeniedHandler accessDeniedHandler;
- private final AuthenticationEntryPoint authenticationEntryPoint;
- private final CustomUserDetailsServiceImpl customUserDetailsServiceImpl;
- private final JwtAuthenticationFilter jwtAuthenticationFilter;
-
- @Bean
- public BCryptPasswordEncoder encoder() {
- return new BCryptPasswordEncoder();
- }
-
- @Bean
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.userDetailsService(customUserDetailsServiceImpl).passwordEncoder(encoder());
- }
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- // Check if disable Web Security.
- if (customConfiguration.getWebSecurityDisabled()) {
- http.authorizeRequests().anyRequest().permitAll().and().csrf().disable();
- return;
- }
-
- http.cors()
- // Disable CSRF (Cross-site request forgery)
- .and().csrf().disable()
- // Disable form login to use custom login
- .formLogin().disable()
- .httpBasic().disable()
-
- // Allows restricting access based upon the HttpServletRequest
- .authorizeRequests()
- // RBAC URL authorization
- .anyRequest()
- .access("@rbacAuthorityServiceImpl.hasPermission(request,authentication)")
-
- // Disable logout to use custom logout
- .and().logout().disable()
- .sessionManagement()
- // Disable session management
- .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
-
- // Exception handling
- .and()
- .exceptionHandling()
- .accessDeniedHandler(accessDeniedHandler)
- .authenticationEntryPoint(authenticationEntryPoint);
-
- // Add customized JWT filter
- http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
- }
-
- /**
- * Add ignored HTTP request list
- * Same as {@link #configure(HttpSecurity)}
- * {@code http.authorizeRequests().antMatchers("/api/auth/**").permitAll()}
- */
- @Override
- public void configure(WebSecurity web) {
- val and = web.ignoring().and();
- Optional.ofNullable(customConfiguration.getIgnoredRequest())
- .ifPresentOrElse((ignoredRequest -> {
- ignoredRequest.getGet().forEach(url -> and.ignoring().antMatchers(HttpMethod.GET, url));
- ignoredRequest.getPost().forEach(url -> and.ignoring().antMatchers(HttpMethod.POST, url));
- ignoredRequest.getDelete().forEach(url -> and.ignoring().antMatchers(HttpMethod.DELETE, url));
- ignoredRequest.getPut().forEach(url -> and.ignoring().antMatchers(HttpMethod.PUT, url));
- ignoredRequest.getHead().forEach(url -> and.ignoring().antMatchers(HttpMethod.HEAD, url));
- ignoredRequest.getPatch().forEach(url -> and.ignoring().antMatchers(HttpMethod.PATCH, url));
- ignoredRequest.getOptions().forEach(url -> and.ignoring().antMatchers(HttpMethod.OPTIONS, url));
- ignoredRequest.getTrace().forEach(url -> and.ignoring().antMatchers(HttpMethod.TRACE, url));
- ignoredRequest.getPattern().forEach(url -> and.ignoring().antMatchers(url));
- }), () -> log.warn("Security warning: Ignored request is empty! The ignored request configuration " +
- "might be invalid!"));
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/controller/CommonController.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/controller/CommonController.java
deleted file mode 100644
index 4567e71a..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/controller/CommonController.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.controller;
-
-import com.jmsoftware.maf.apiportal.universal.domain.ValidationTestPayload;
-import com.jmsoftware.maf.apiportal.universal.service.CommonService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.Map;
-
-/**
- *
CommonController
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2/4/20 10:29 AM
- **/
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/common")
-@Api(tags = {"Common Controller"})
-public class CommonController {
- private final CommonService commonService;
-
- @GetMapping("/app-info")
- @ApiOperation(value = "/app-info", notes = "Retrieve application information")
- public ResponseBodyBean> applicationInformation() {
- val data = commonService.getApplicationInfo();
- return ResponseBodyBean.ofSuccess(data, "Succeed to retrieve app info.");
- }
-
- @PostMapping("/validation-test")
- @ApiOperation(value = "/validation-test", notes = "Validation of request payload test")
- public ResponseBodyBean validationTest(@RequestBody ValidationTestPayload payload) {
- commonService.validateObject(payload);
- return ResponseBodyBean.ofSuccess(payload.getName(), "validationTest()");
- }
-
- @GetMapping("/get-jwt")
- @ApiOperation(value = "/get-jwt", notes = "Get JWT")
- public ResponseBodyBean getJwt(String username) {
- return ResponseBodyBean.ofSuccess(commonService.generateJwt(username));
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/controller/ErrorController.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/controller/ErrorController.java
deleted file mode 100644
index dc90f00a..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/controller/ErrorController.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.controller;
-
-import io.swagger.annotations.Api;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.boot.autoconfigure.web.ServerProperties;
-import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
-import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
-import org.springframework.boot.web.servlet.error.ErrorAttributes;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-/**
- * ErrorController
- *
- * Error controller.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-02 16:56
- **/
-@Slf4j
-@RestController
-@Api(tags = {"Error Controller"})
-public class ErrorController extends BasicErrorController {
- public ErrorController(ErrorAttributes errorAttributes,
- ServerProperties serverProperties,
- List errorViewResolvers) {
- super(errorAttributes, serverProperties.getError(), errorViewResolvers);
- }
-
- @Override
- public ResponseEntity> error(HttpServletRequest request) {
- val httpStatus = getStatus(request);
- val body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
- body.put("message", httpStatus.getReasonPhrase());
- val optionalTrace = Optional.ofNullable(body.get("trace"));
- optionalTrace.ifPresent(trace -> {
- val message = body.get("message");
- val firstLineOfTrace = trace.toString().split("\\n")[0];
- val joinedMessage = String.format("%s %s", message, firstLineOfTrace);
- body.put("message", joinedMessage);
- body.put("trace", "Trace has been simplified. Refer to 'message'");
- });
- log.error("Captured HTTP request error. Response body = {}", body);
- return new ResponseEntity<>(body, httpStatus);
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/domain/SftpSubDirectory.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/domain/SftpSubDirectory.java
deleted file mode 100644
index f4d4fac8..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/domain/SftpSubDirectory.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.domain;
-
-import lombok.Getter;
-
-/**
- * SftpSubDirectory
- * Reminder: if you want to add more custom sub directories in the future, please add en enum item in this class
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-04 23:10
- **/
-@Getter
-public enum SftpSubDirectory {
- /**
- * Sub directory for video
- */
- VIDEO("video", "/video/"),
- /**
- * Sub directory for avatar
- */
- AVATAR("avatar", "/avatar/");
-
- private final String directoryName;
- private final String subDirectory;
-
- SftpSubDirectory(String directoryName, String subDirectory) {
- this.directoryName = directoryName;
- this.subDirectory = subDirectory;
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/domain/ValidationTestPayload.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/domain/ValidationTestPayload.java
deleted file mode 100644
index 53584358..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/domain/ValidationTestPayload.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.domain;
-
-import lombok.Data;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-
-/**
- * ValidationTestPayload
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2/14/20 11:34 AM
- **/
-@Data
-public class ValidationTestPayload {
- @NotNull
- @Min(value = 1L)
- private Long id;
- @NotEmpty
- private String name;
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/filter/JwtAuthenticationFilter.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/filter/JwtAuthenticationFilter.java
deleted file mode 100644
index 54718b75..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/filter/JwtAuthenticationFilter.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.filter;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.jmsoftware.maf.apiportal.universal.configuration.CustomConfiguration;
-import com.jmsoftware.maf.apiportal.universal.service.impl.CustomUserDetailsServiceImpl;
-import com.jmsoftware.maf.apiportal.universal.service.impl.JwtServiceImpl;
-import com.jmsoftware.maf.common.constant.HttpStatus;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import com.jmsoftware.maf.muscleandfitnessserverspringbootstarter.util.RequestUtil;
-import com.jmsoftware.maf.muscleandfitnessserverspringbootstarter.util.ResponseUtil;
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.stereotype.Component;
-import org.springframework.web.filter.OncePerRequestFilter;
-
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Optional;
-
-/**
- *
JwtAuthenticationFilter
- * Jwt Authentication Filter.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-23 14:24
- **/
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class JwtAuthenticationFilter extends OncePerRequestFilter {
- private final CustomUserDetailsServiceImpl customUserDetailsServiceImpl;
- private final JwtServiceImpl jwtServiceImpl;
- private final CustomConfiguration customConfiguration;
-
- @Override
- @SuppressWarnings("NullableProblems")
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
- FilterChain filterChain) throws ServletException, IOException {
- val requesterIpAndPort = RequestUtil.getRequestIpAndPort(request);
- val method = request.getMethod();
- val requestUrl = request.getRequestURL();
- log.info("JWT authentication is filtering requester({}) access. Resource: [{}] {}",
- requesterIpAndPort, method, requestUrl);
- if (customConfiguration.getWebSecurityDisabled()) {
- log.warn("The web security is disabled! Might face severe web security issue.");
- filterChain.doFilter(request, response);
- return;
- }
- if (checkIgnores(request)) {
- log.info("The resource can be ignored. Resource: [{}] {}", method, requestUrl);
- filterChain.doFilter(request, response);
- return;
- }
- val passedJwtAuthentication = doJwtAuthentication(request, response);
- if (!passedJwtAuthentication) {
- log.warn("The requester did not pass JWT authentication. Requester: {}. Resource: [{}] {}", requesterIpAndPort,
- method, requestUrl);
- return;
- }
- try {
- filterChain.doFilter(request, response);
- } catch (Exception e) {
- log.error("Exception occurred when filtering request. Exception message: {}", e.getMessage(), e);
- val exception = recursiveTraverseExceptionCause(e);
- if (exception instanceof SecurityException) {
- val code = ((SecurityException) exception).getCode();
- final var httpStatus = HttpStatus.fromCode(code);
- ResponseUtil.renderJson(response, httpStatus, exception.getMessage());
- return;
- }
- ResponseUtil.renderJson(response, HttpStatus.ERROR, e.getMessage());
- }
- }
-
- /**
- * Do JWT authentication. This method will not throw any exceptions.
- *
- * @param request the request
- * @param response the response
- * @return the boolean
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
- * @date 5 /13/20 5:30 PM
- */
- private boolean doJwtAuthentication(HttpServletRequest request, HttpServletResponse response) {
- val jwt = jwtServiceImpl.getJwtFromRequest(request);
- if (StrUtil.isBlank(jwt)) {
- log.error("Invalid JWT, the JWT of request is empty.");
- ResponseUtil.renderJson(response, HttpStatus.UNAUTHORIZED, HttpStatus.UNAUTHORIZED.getMessage());
- return false;
- }
- String username;
- try {
- username = jwtServiceImpl.getUsernameFromJwt(jwt);
- } catch (SecurityException e) {
- log.error("Exception occurred when getting username from JWT. Exception message: {} JWT: {}",
- e.getMessage(), jwt);
- var httpStatus = HttpStatus.fromCode(e.getCode());
- ResponseUtil.renderJson(response, httpStatus, httpStatus.getMessage());
- return false;
- }
- UserDetails userDetails;
- try {
- userDetails = customUserDetailsServiceImpl.loadUserByUsername(username);
- } catch (Exception e) {
- log.error("Exception occurred when loading user by username! Exception message: {} Username: {}",
- e.getMessage(), username);
- if (e instanceof UsernameNotFoundException) {
- ResponseUtil.renderJson(response, HttpStatus.UNAUTHORIZED, HttpStatus.UNAUTHORIZED.getMessage());
- return false;
- }
- ResponseUtil.renderJson(response, HttpStatus.ERROR, e.getMessage());
- return false;
- }
- val authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
- authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
- log.info("JWT authentication passed! Authentication: {}", authentication);
- SecurityContextHolder.getContext().setAuthentication(authentication);
- return true;
- }
-
- /**
- * Check if current request needs to be ignored. (Permission interception)
- *
- * @param request Current request
- * @return true - Ignored, false - Not ignored
- */
- private boolean checkIgnores(HttpServletRequest request) {
- val method = request.getMethod();
- var httpMethod = HttpMethod.resolve(method);
- if (ObjectUtil.isNull(httpMethod)) {
- httpMethod = HttpMethod.GET;
- }
- val ignoredRequestSet = new HashSet();
- val finalHttpMethod = httpMethod;
- Optional.ofNullable(customConfiguration.getIgnoredRequest())
- .ifPresentOrElse((ignoredRequest -> {
- ignoredRequestSet.addAll(ignoredRequest.getPattern());
- switch (finalHttpMethod) {
- case GET:
- ignoredRequestSet.addAll(ignoredRequest.getGet());
- break;
- case PUT:
- ignoredRequestSet.addAll(ignoredRequest.getPut());
- break;
- case HEAD:
- ignoredRequestSet.addAll(ignoredRequest.getHead());
- break;
- case POST:
- ignoredRequestSet.addAll(ignoredRequest.getPost());
- break;
- case PATCH:
- ignoredRequestSet.addAll(ignoredRequest.getPatch());
- break;
- case TRACE:
- ignoredRequestSet.addAll(ignoredRequest.getTrace());
- break;
- case DELETE:
- ignoredRequestSet.addAll(ignoredRequest.getDelete());
- break;
- case OPTIONS:
- ignoredRequestSet.addAll(ignoredRequest.getOptions());
- break;
- default:
- break;
- }
- }), () -> log.warn("Security warning: Ignored request is empty! The ignored request configuration " +
- "might be invalid!"));
- if (CollUtil.isNotEmpty(ignoredRequestSet)) {
- for (val ignore : ignoredRequestSet) {
- val matcher = new AntPathRequestMatcher(ignore, method);
- if (matcher.matches(request)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Recursive traverse exception cause exception.
- *
- * @param exception the exception
- * @return the exception
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
- * @date 5/13/20 4:51 PM
- */
- private Exception recursiveTraverseExceptionCause(@NonNull Exception exception) {
- if (ObjectUtil.isNotNull(exception.getCause())) {
- return recursiveTraverseExceptionCause((Exception) exception.getCause());
- }
- return exception;
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/CommonService.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/CommonService.java
deleted file mode 100644
index 3b123344..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/CommonService.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service;
-
-import com.jmsoftware.maf.apiportal.universal.domain.ValidationTestPayload;
-import org.springframework.validation.annotation.Validated;
-
-import javax.validation.Valid;
-import java.util.Map;
-
-/**
- * CommonService
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2/4/20 11:15 AM
- */
-@Validated
-public interface CommonService {
- /**
- * Gets application info.
- *
- * @return the application info.
- */
- Map getApplicationInfo();
-
- /**
- * Validate object.
- *
- * @param payload the payload
- */
- void validateObject(@Valid ValidationTestPayload payload);
-
- /**
- * Generate jwt string.
- *
- * @param username the username
- * @return the string
- */
- String generateJwt(String username);
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/JwtService.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/JwtService.java
deleted file mode 100644
index 86735c9f..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/JwtService.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service;
-
-import com.jmsoftware.maf.common.exception.SecurityException;
-import io.jsonwebtoken.Claims;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * JwtService
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/7/20 5:15 PM
- */
-public interface JwtService {
- /**
- * Create JWT string.
- *
- * @param authentication the authentication
- * @param rememberMe the remember me
- * @return the string
- */
- String createJwt(Authentication authentication, Boolean rememberMe) throws SecurityException;
-
- /**
- * Create JWT string.
- *
- * @param rememberMe the remember me
- * @param id the user ID
- * @param subject the username
- * @param roles the roles
- * @param authorities the authorities
- * @return the JWT string
- */
- String createJwt(Boolean rememberMe, Long id, String subject, List roles, Collection
- extends GrantedAuthority> authorities) throws SecurityException;
-
- /**
- * Parse JWT.
- *
- * @param jwt the jwt
- * @return the claims
- */
- Claims parseJwt(String jwt) throws SecurityException;
-
- /**
- * Invalidate jwt.
- *
- * @param request the request
- */
- void invalidateJwt(HttpServletRequest request) throws SecurityException;
-
- /**
- * Gets username from jwt.
- *
- * @param jwt the jwt
- * @return the username from jwt
- */
- String getUsernameFromJwt(String jwt) throws SecurityException;
-
- /**
- * Gets username from request.
- *
- * @param request the request
- * @return the username from request
- */
- String getUsernameFromRequest(HttpServletRequest request) throws SecurityException;
-
- /**
- * Gets jwt from request.
- *
- * @param request the request
- * @return the jwt from request
- */
- String getJwtFromRequest(HttpServletRequest request);
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/RbacAuthorityService.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/RbacAuthorityService.java
deleted file mode 100644
index 03e105b5..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/RbacAuthorityService.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service;
-
-import org.springframework.security.core.Authentication;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * RbacAuthorityService
- * Route Authority service interface
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-04-07 19:52
- **/
-public interface RbacAuthorityService {
- /**
- * Check whether the user from request has permission
- *
- * @param request HTTP request
- * @param authentication authentication
- * @return true - the user has permission; false - the user do not have permission
- */
- boolean hasPermission(HttpServletRequest request, Authentication authentication);
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/RedisService.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/RedisService.java
deleted file mode 100644
index ece5168c..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/RedisService.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * RedisService
- * Redis service interface for Redis useful operations
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-05 09:38
- **/
-public interface RedisService {
- /**
- * Set key and value in Redis with expiration
- *
- * @param key key
- * @param value value
- * @param expirationTime expiration time
- * @param timeUnit time unit
- * @return true - operation done; false - operation failure
- */
- Boolean set(String key, String value, Long expirationTime, TimeUnit timeUnit);
-
- /**
- * Set key and list in Redis with expiration
- *
- * @param key key
- * @param list list
- * @param expirationTime expiration time
- * @param timeUnit time unit
- * @return true - operation done; false - operation failure
- */
- Boolean set(String key, List list, Long expirationTime, TimeUnit timeUnit);
-
- /**
- * Set key and value in Redis
- *
- * @param key key
- * @param value value
- * @return true - operation done; false - operation failure
- */
- Boolean set(String key, String value);
-
- /**
- * Set key and list in Redis
- *
- * @param key key
- * @param list list
- * @return true - operation done; false - operation failure
- */
- Boolean set(String key, List list);
-
- /**
- * Make key expire
- *
- * @param key key
- * @param expirationTime expiration time
- * @param timeUnit time unit
- * @return true - operation done; false - operation failure
- */
- Boolean expire(String key, long expirationTime, TimeUnit timeUnit);
-
- /**
- * Get expiration time by key
- *
- * @param key key
- * @param timeUnit time unit
- * @return expiration time. Null when used in pipeline / transaction.
- */
- Long getExpire(String key, TimeUnit timeUnit);
-
- /**
- * Get value by key
- *
- * @param key key
- * @return null when key does not exist or used in pipeline / transaction.
- */
- String get(String key);
-
- /**
- * Get list by key
- *
- * @param key key
- * @param clazz type
- * @return null when key does not exist or used in pipeline / transaction.
- */
- List get(String key, Class clazz);
-
- /**
- * Delete by key
- *
- * @param key key
- * @return the number of keys that were removed. Null when used in pipeline / transaction.
- */
- Long delete(String key);
-
- /**
- * Delete by keys
- *
- * @param keys key list
- * @return the number of keys that were removed. Null when used in pipeline / transaction.
- */
- Long delete(Collection keys);
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/SftpService.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/SftpService.java
deleted file mode 100644
index 273bfc88..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/SftpService.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service;
-
-import com.jmsoftware.maf.apiportal.universal.domain.SftpUploadFile;
-import org.springframework.integration.file.support.FileExistsMode;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.validation.Valid;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-
-/**
- * SftpService
- * SFTP service interface
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-04 20:35
- **/
-@Validated
-public interface SftpService {
- /**
- * List all files under the full path
- *
- * @param fullPath directory full path
- * @return file names
- */
- List listFiles(String fullPath);
-
- /**
- * Check whether file exists according to file path
- *
- * @param fileFullPath file's full path
- * @return true - file exists; false - file not exists
- */
- boolean exist(String fileFullPath);
-
- /**
- * Get file size
- *
- * @param fileFullPath file's full path
- * @return file size (size unit: byte). Null if the file does not exist or path refers to a directory
- * @throws IllegalArgumentException when file does not exist
- */
- Long getFileSize(String fileFullPath) throws IllegalArgumentException;
-
- /**
- * Upload single file
- *
- * @param sftpUploadFile encapsulated object
- * @return file's full path if successful, else null
- */
- String upload(@Valid SftpUploadFile sftpUploadFile);
-
- /**
- * Upload file
- *
- * @param multipartFile multipart file
- * @param subDirectory SFTP server's sub directory (if sub directory doesn't exist, will be auto created). Not
- * empty and it looks like this: "/some/sub/directory/"
- * @param fileExistsMode This enumeration indicates what action shall be taken in case the destination file
- * already exists. In default, it should be set as: FileExistsMode.REPLACE
- * @param deleteSource true - delete source file; false - not delete source file
- * @return file's full path if successful, else null
- * @throws IOException IO exception
- */
- String upload(MultipartFile multipartFile,
- String subDirectory,
- FileExistsMode fileExistsMode,
- boolean deleteSource) throws IOException;
-
- /**
- * Upload files
- *
- * @param files file list
- * @throws IOException IO exception
- */
- void upload(List files) throws IOException;
-
- /**
- * Upload files
- *
- * @param files file list
- * @param deleteSource true - delete source file; false - not delete source file
- * @throws IOException IO exception
- */
- void upload(List files, boolean deleteSource) throws IOException;
-
- /**
- * Read file from SFTP server
- *
- * @param fileFullPath file's full path
- * @return file's stream
- * @throws IllegalArgumentException when file does not exist
- */
- InputStream read(String fileFullPath) throws IllegalArgumentException;
-
- /**
- * Delete file according to file path
- *
- * @param fileFullPath file's full path
- * @return true - file deleted; false - file not deleted
- */
- boolean delete(String fileFullPath);
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/CommonServiceImpl.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/CommonServiceImpl.java
deleted file mode 100644
index 19b2605b..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/CommonServiceImpl.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service.impl;
-
-import com.google.common.collect.Lists;
-import com.jmsoftware.maf.apiportal.universal.configuration.ProjectProperty;
-import com.jmsoftware.maf.apiportal.universal.domain.ValidationTestPayload;
-import com.jmsoftware.maf.apiportal.universal.service.CommonService;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import javax.validation.Valid;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * CommonServiceImpl
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2/4/20 11:16 AM
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class CommonServiceImpl implements CommonService {
- private final ProjectProperty projectProperty;
- private final JwtServiceImpl jwtServiceImpl;
-
- @Override
- public Map getApplicationInfo() {
- var map = new HashMap(16);
- var fieldsInfo = getFieldsInfo(projectProperty);
- fieldsInfo.forEach(fieldInfo -> {
- var type = fieldInfo.get("type");
- if ("class java.lang.String".equals(type)) {
- map.put((String) fieldInfo.get("name"), fieldInfo.get("value"));
- }
- });
- return map;
- }
-
- @Override
- public void validateObject(@Valid ValidationTestPayload payload) {
- log.info("Validation passed! {}", payload);
- }
-
- @Override
- @SneakyThrows
- public String generateJwt(String username) {
- return jwtServiceImpl.createJwt(false, Long.MAX_VALUE, username, Lists.newLinkedList(), Lists.newLinkedList());
- }
-
- /**
- * Gets field value by name.
- *
- * @param fieldName the field name
- * @param object the object
- * @return the field value by name
- * @see Java 中遍历一个对象的所有属性
- */
- private Object getFieldValueByName(String fieldName, Object object) {
- try {
- String firstLetter = fieldName.substring(0, 1).toUpperCase();
- String getter = "get" + firstLetter + fieldName.substring(1);
- Method method = object.getClass().getMethod(getter);
- return method.invoke(object);
- } catch (Exception e) {
- log.error("Can't get field's value by name! Cause: {}", e.getMessage());
- return null;
- }
- }
-
- /**
- * Get filed name string [ ].
- *
- * @param o the o
- * @return the string [ ]
- * @see Java 中遍历一个对象的所有属性
- */
- private String[] getFiledName(Object o) {
- Field[] fields = o.getClass().getDeclaredFields();
- String[] fieldNames = new String[fields.length];
- for (int i = 0; i < fields.length; i++) {
- log.info("fields[i].getType(): {}", fields[i].getType());
- fieldNames[i] = fields[i].getName();
- }
- return fieldNames;
- }
-
- /**
- * Get Fields Info
- *
- * @param o the o
- * @return the fields info
- * @see Java 中遍历一个对象的所有属性
- */
- private List> getFieldsInfo(Object o) {
- Field[] fields = o.getClass().getDeclaredFields();
- var arrayList = new ArrayList>();
- for (Field field : fields) {
- var infoMap = new HashMap(16);
- infoMap.put("type", field.getType().toString());
- infoMap.put("name", field.getName());
- infoMap.put("value", getFieldValueByName(field.getName(), o));
- arrayList.add(infoMap);
- }
- return arrayList;
- }
-
- /**
- * Get Filed Values
- *
- * @param o the o
- * @return the object [ ]
- * @see Java 中遍历一个对象的所有属性
- */
- public Object[] getFiledValues(Object o) {
- String[] fieldNames = this.getFiledName(o);
- Object[] value = new Object[fieldNames.length];
- for (int i = 0; i < fieldNames.length; i++) {
- value[i] = this.getFieldValueByName(fieldNames[i], o);
- }
- return value;
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/CustomUserDetailsServiceImpl.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/CustomUserDetailsServiceImpl.java
deleted file mode 100644
index 18dd03c8..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/CustomUserDetailsServiceImpl.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import com.jmsoftware.maf.apiportal.remoteapi.AuthCenterRemoteApi;
-import com.jmsoftware.maf.apiportal.universal.domain.UserPrincipal;
-import com.jmsoftware.maf.common.constant.HttpStatus;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdPayload;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse;
-import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenPayload;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.stereotype.Service;
-
-import java.util.stream.Collectors;
-
-/**
- * CustomUserDetailsServiceImpl
- * Custom user detail service.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-03 13:40
- **/
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class CustomUserDetailsServiceImpl implements UserDetailsService {
- private final AuthCenterRemoteApi authCenterRemoteApi;
-
- @Override
- @SneakyThrows
- public UserDetails loadUserByUsername(String credentials) throws UsernameNotFoundException {
- val getUserByLoginTokenPayload = new GetUserByLoginTokenPayload();
- getUserByLoginTokenPayload.setLoginToken(credentials);
- val getUserByLoginTokenResponseResponseBody =
- authCenterRemoteApi.getUserByLoginToken(getUserByLoginTokenPayload);
- val getUserByLoginTokenResponse = getUserByLoginTokenResponseResponseBody.getData();
- if (ObjectUtil.isNull(getUserByLoginTokenResponse)) {
- val errorMessage = String.format("User's account not found, credentials: %s", credentials);
- log.error(errorMessage);
- throw new UsernameNotFoundException(errorMessage);
- }
- val getRoleListByUserIdPayload = new GetRoleListByUserIdPayload();
- getRoleListByUserIdPayload.setUserId(getUserByLoginTokenResponse.getId());
- val getRoleListByUserIdResponseResponseBody =
- authCenterRemoteApi.getRoleListByUserId(getRoleListByUserIdPayload);
- val roleList = getRoleListByUserIdResponseResponseBody.getData().getRoleList();
- if (CollUtil.isEmpty(roleList)) {
- throw new SecurityException(HttpStatus.ROLE_NOT_FOUND);
- }
- val getPermissionListByRoleIdListPayload = new GetPermissionListByRoleIdListPayload();
- roleList.forEach(role -> getPermissionListByRoleIdListPayload.getRoleIdList().add(role.getId()));
- val permissionListByRoleIdListResponseBody =
- authCenterRemoteApi.getPermissionListByRoleIdList(getPermissionListByRoleIdListPayload);
- val roleNameList =
- roleList.stream().map(GetRoleListByUserIdResponse.Role::getName).collect(Collectors.toList());
- return UserPrincipal.create(getUserByLoginTokenResponse, roleNameList,
- permissionListByRoleIdListResponseBody.getData().getPermissionList());
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/RbacAuthorityServiceImpl.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/RbacAuthorityServiceImpl.java
deleted file mode 100644
index 18f2e275..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/RbacAuthorityServiceImpl.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service.impl;
-
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.Multimap;
-import com.jmsoftware.maf.apiportal.remoteapi.AuthCenterRemoteApi;
-import com.jmsoftware.maf.apiportal.universal.configuration.CustomConfiguration;
-import com.jmsoftware.maf.apiportal.universal.domain.UserPrincipal;
-import com.jmsoftware.maf.apiportal.universal.service.RbacAuthorityService;
-import com.jmsoftware.maf.common.constant.HttpStatus;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.stereotype.Service;
-import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.stream.Collectors;
-
-/**
- * RbacAuthorityServiceImpl
- * Route Authority service implementation
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-23 14:25
- **/
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class RbacAuthorityServiceImpl implements RbacAuthorityService {
- private final AuthCenterRemoteApi authCenterRemoteApi;
- private final RequestMappingHandlerMapping mapping;
- private final CustomConfiguration customConfiguration;
- private final JwtServiceImpl jwtServiceImpl;
-
- @Override
- @SneakyThrows
- public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
- String username;
- try {
- username = jwtServiceImpl.getUsernameFromRequest(request);
- } catch (SecurityException e) {
- log.error("Exception occurred when getting username from request. Exception message: {}", e.getMessage());
- throw e;
- }
- // Super user has no restriction on any requests.
- if (customConfiguration.getSuperUser().equals(username)) {
- log.info("Superuser(username: {}) can access any resource.", username);
- return true;
- }
- this.checkRequest(request);
- val principal = authentication.getPrincipal();
- if (!(principal instanceof UserDetails)) {
- log.error("Invalid user principal. {}", principal);
- return false;
- }
- val userPrincipal = (UserPrincipal) principal;
- val userId = userPrincipal.getId();
- val getPermissionListByUserIdPayload = new GetPermissionListByUserIdPayload();
- getPermissionListByUserIdPayload.setUserId(userId);
- val getPermissionListByUserIdResponse =
- authCenterRemoteApi.getPermissionListByUserId(getPermissionListByUserIdPayload);
- val permissionList = getPermissionListByUserIdResponse.getData().getPermissionList();
- // Filter button permission for frond-end
- val buttonPermissionList = permissionList.stream()
- // Sieve out page permissions
- .filter(permission -> ObjectUtil.equal(permission.getType(),
- PermissionType.BUTTON.getType()))
- // Sieve out permission that has no URL
- .filter(permission -> StrUtil.isNotBlank(permission.getUrl()))
- // Sieve out permission that has no method
- .filter(permission -> StrUtil.isNotBlank(permission.getMethod()))
- .collect(Collectors.toList());
- for (val buttonPermission : buttonPermissionList) {
- // TODO: check is AntPathRequestMatcher supports RESTFul request
- val antPathMatcher = new AntPathRequestMatcher(buttonPermission.getUrl(), buttonPermission.getMethod());
- if (antPathMatcher.matches(request)) {
- log.info("Resource [{}] {} is accessible for user(username: {})", request.getMethod(),
- request.getRequestURL(), username);
- return true;
- }
- }
- log.warn("Resource [{}] {} is not accessible for user(username: {})", request.getMethod(),
- request.getRequestURL(), username);
- return false;
- }
-
- /**
- * Check request.
- *
- * @param request HTTP Request
- */
- @SneakyThrows
- private void checkRequest(HttpServletRequest request) {
- val currentMethod = request.getMethod();
- val urlMapping = allUrlMapping();
- for (String uri : urlMapping.keySet()) {
- // 通过 AntPathRequestMatcher 匹配 url
- // 可以通过 2 种方式创建 AntPathRequestMatcher
- // 1:new AntPathRequestMatcher(uri,method) 这种方式可以直接判断方法是否匹配,
- // 因为这里我们把 方法不匹配 自定义抛出,所以,我们使用第2种方式创建
- // 2:new AntPathRequestMatcher(uri) 这种方式不校验请求方法,只校验请求路径
- val antPathMatcher = new AntPathRequestMatcher(uri);
- if (antPathMatcher.matches(request)) {
- if (!urlMapping.get(uri).contains(currentMethod)) {
- throw new SecurityException(HttpStatus.METHOD_NOT_ALLOWED);
- } else {
- return;
- }
- }
- }
- throw new SecurityException(HttpStatus.NOT_FOUND);
- }
-
- /**
- * 获取 所有URL Mapping,返回格式为{"/test":["GET","POST"],"/sys":["GET","DELETE"]}
- *
- * @return {@link ArrayListMultimap} 格式的 URL Mapping
- */
- private Multimap allUrlMapping() {
- Multimap urlMapping = LinkedListMultimap.create();
- // 获取url与类和方法的对应信息
- val handlerMethods = mapping.getHandlerMethods();
- handlerMethods.forEach((key, value) -> {
- // 获取当前 key 下的获取所有URL
- val url = key.getPatternsCondition().getPatterns();
- val method = key.getMethodsCondition();
- // 为每个URL添加所有的请求方法
- url.forEach(item -> urlMapping.putAll(item,
- method.getMethods().stream().map(Enum::toString).collect(Collectors.toList())));
- });
- return urlMapping;
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/RedisServiceImpl.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/RedisServiceImpl.java
deleted file mode 100644
index b6e5352d..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/RedisServiceImpl.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service.impl;
-
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONUtil;
-import com.jmsoftware.maf.apiportal.universal.service.RedisService;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.data.redis.connection.RedisStringCommands;
-import org.springframework.data.redis.core.RedisCallback;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.types.Expiration;
-import org.springframework.data.redis.serializer.RedisSerializer;
-import org.springframework.stereotype.Service;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-
-/**
- * RedisServiceImpl
- * Redis service implementation for Redis useful operations
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-05 09:39
- **/
-@Service
-public class RedisServiceImpl implements RedisService {
- private final RedisTemplate redisTemplate;
-
- public RedisServiceImpl(@Qualifier("redisFactory") RedisTemplate redisTemplate) {
- this.redisTemplate = redisTemplate;
- }
-
- @Override
- public Boolean set(String key, String value, Long expirationTime, TimeUnit timeUnit) {
- return redisTemplate.execute((RedisCallback) connection -> {
- RedisSerializer serializer = redisTemplate.getStringSerializer();
- Boolean result = connection.set(Objects.requireNonNull(serializer.serialize(key)),
- Objects.requireNonNull(serializer.serialize(value)),
- Expiration.from(expirationTime, timeUnit),
- RedisStringCommands.SetOption.upsert());
- return ObjectUtil.isNotNull(result) ? result : false;
- });
- }
-
- @Override
- public Boolean set(String key, List list, Long expirationTime, TimeUnit timeUnit) {
- String value = JSONUtil.toJsonStr(list);
- return set(key, value, expirationTime, timeUnit);
- }
-
- @Override
- public Boolean set(String key, String value) {
- return redisTemplate.execute((RedisCallback) connection -> {
- RedisSerializer serializer = redisTemplate.getStringSerializer();
- Boolean result = connection.set(Objects.requireNonNull(serializer.serialize(key)),
- Objects.requireNonNull(serializer.serialize(value)));
- return ObjectUtil.isNotNull(result) ? result : false;
- });
- }
-
- @Override
- public Boolean set(String key, List list) {
- String value = JSONUtil.toJsonStr(list);
- return set(key, value);
- }
-
- @Override
- public Boolean expire(String key, long expirationTime, TimeUnit timeUnit) {
- Boolean result = redisTemplate.expire(key, expirationTime, timeUnit);
- return ObjectUtil.isNotNull(result) ? result : false;
- }
-
- @Override
- public Long getExpire(String key, TimeUnit timeUnit) {
- return redisTemplate.getExpire(key, timeUnit);
- }
-
- @Override
- public String get(String key) {
- return redisTemplate.execute((RedisCallback) connection -> {
- RedisSerializer serializer = redisTemplate.getStringSerializer();
- byte[] bytes = connection.get(Objects.requireNonNull(serializer.serialize(key)));
- return serializer.deserialize(bytes);
- });
- }
-
- @Override
- public List get(String key, Class clazz) {
- String json = get(key);
- if (StrUtil.isNotBlank(json)) {
- return JSONUtil.toList(JSONUtil.parseArray(json), clazz);
- }
- return null;
- }
-
- @Override
- public Long delete(String key) {
- return redisTemplate.execute((RedisCallback) connection -> {
- RedisSerializer serializer = redisTemplate.getStringSerializer();
- return connection.del(serializer.serialize(key));
- });
- }
-
- @Override
- public Long delete(Collection keys) {
- return redisTemplate.delete(keys);
- }
-}
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/SftpServiceImpl.java b/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/SftpServiceImpl.java
deleted file mode 100644
index 882cf871..00000000
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/SftpServiceImpl.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.jmsoftware.maf.apiportal.universal.service.impl;
-
-import com.jcraft.jsch.ChannelSftp;
-import com.jmsoftware.maf.apiportal.universal.configuration.SftpClientConfiguration;
-import com.jmsoftware.maf.apiportal.universal.configuration.SftpUploadGateway;
-import com.jmsoftware.maf.apiportal.universal.domain.SftpUploadFile;
-import com.jmsoftware.maf.apiportal.universal.service.SftpService;
-import com.jmsoftware.maf.muscleandfitnessserverspringbootstarter.util.FileUtil;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.expression.common.LiteralExpression;
-import org.springframework.integration.file.support.FileExistsMode;
-import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
-import org.springframework.messaging.Message;
-import org.springframework.messaging.support.MessageBuilder;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.validation.Valid;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * SftpServiceImpl
- * SFTP Service implementation
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-04 20:47
- **/
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class SftpServiceImpl implements SftpService {
- private final SftpRemoteFileTemplate sftpRemoteFileTemplate;
- private final SftpUploadGateway sftpUploadGateway;
- private final SftpClientConfiguration sftpClientConfiguration;
- private final BeanFactory beanFactory;
-
- @Override
- public List listFiles(String fullPath) {
- log.info("Listing files, full path: {}", fullPath);
- return sftpRemoteFileTemplate.execute(session -> {
- String[] strings = new String[0];
- try {
- strings = session.listNames(fullPath);
- } catch (IOException e) {
- log.error("Exception occurred when listing files. Exception message: {}", e.getMessage(), e);
- }
- return Arrays.asList(strings);
- });
- }
-
- @Override
- public boolean exist(String fileFullPath) {
- log.info("Checking whether file exists in SFTP server, file full path: {}", fileFullPath);
- return sftpRemoteFileTemplate.execute(session -> session.exists(fileFullPath));
- }
-
- @Override
- public Long getFileSize(String fileFullPath) throws IllegalArgumentException {
- if (!exist(fileFullPath)) {
- throw new IllegalArgumentException(
- "Cannot get file size from SFTP server. Caused by: file does not exist, full path: " + fileFullPath);
- }
- String[] splits = fileFullPath.split("/");
- String fileName = splits[splits.length - 1];
- String listPath = fileFullPath.substring(0, fileFullPath.lastIndexOf(fileName) - 1);
- log.info("Retrieve file size from SFTP server, full path: {}", fileFullPath);
- final Long[] fileSize = new Long[1];
- sftpRemoteFileTemplate.execute(session -> {
- ChannelSftp.LsEntry[] lsEntries = session.list(listPath);
- for (ChannelSftp.LsEntry lsEntry : lsEntries) {
- if (lsEntry.getFilename().equals(fileName)) {
- fileSize[0] = lsEntry.getAttrs().getSize();
- }
- }
- return null;
- });
- return fileSize[0];
- }
-
- @Override
- public String upload(@Valid SftpUploadFile sftpUploadFile) {
- log.info("Uploading single file to SFTP server. SftpUploadFile: {}", sftpUploadFile);
- Message message = MessageBuilder.withPayload(sftpUploadFile.getFileToBeUploaded()).build();
- sftpRemoteFileTemplate.setRemoteDirectoryExpression(
- new LiteralExpression(sftpClientConfiguration.getDirectory()));
- sftpRemoteFileTemplate.setAutoCreateDirectory(true);
- sftpRemoteFileTemplate.setBeanFactory(beanFactory);
- // sftpRemoteFileTemplate.setCharset("UTF-8");
- sftpRemoteFileTemplate.afterPropertiesSet();
- return sftpRemoteFileTemplate.send(message,
- sftpUploadFile.getSubDirectory(),
- sftpUploadFile.getFileExistsMode());
- }
-
- @Override
- @SuppressWarnings("ResultOfMethodCallIgnored")
- public String upload(MultipartFile multipartFile,
- String subDirectory,
- FileExistsMode fileExistsMode,
- boolean deleteSource) throws IOException {
- log.info("Uploading single multipart file to SFTP server. File name: {}", multipartFile.getOriginalFilename());
- File file = FileUtil.convertFrom(multipartFile);
- SftpUploadFile sftpUploadFile = SftpUploadFile
- .builder()
- .fileToBeUploaded(file)
- .subDirectory(subDirectory)
- .fileExistsMode(fileExistsMode)
- .build();
- String fileFullPath = this.upload(sftpUploadFile);
- if (deleteSource) {
- file.delete();
- }
- return fileFullPath;
- }
-
- @Override
- public void upload(List files) throws IOException {
- upload(files, true);
- }
-
- @Override
- @SuppressWarnings("ResultOfMethodCallIgnored")
- public void upload(List files, boolean deleteSource) throws IOException {
- log.info("Uploading multipart files to SFTP server (delete source file: {}). Files: {}", deleteSource, files);
- for (MultipartFile multipartFile : files) {
- if (multipartFile.isEmpty()) {
- continue;
- }
- File file = FileUtil.convertFrom(multipartFile);
- sftpUploadGateway.upload(file);
- if (deleteSource) {
- file.delete();
- }
- }
- }
-
- @Override
- public InputStream read(String fileFullPath) throws IllegalArgumentException {
- log.info("Read file from SFTP server, file full path: {}", fileFullPath);
- return sftpRemoteFileTemplate.execute(session -> {
- boolean existFile = session.exists(fileFullPath);
- if (existFile) {
- return session.readRaw(fileFullPath);
- }
- log.error("Cannot read file from SFTP 'server. Caused by : file does not exist, full path: {}",
- fileFullPath);
- throw new IllegalArgumentException(
- "Cannot read file from SFTP 'server. Caused by : file does not exist, full path: " + fileFullPath);
- });
- }
-
- @Override
- public boolean delete(String fileFullPath) {
- log.info("Deleting SFTP server's file by file full path: {}", fileFullPath);
- return sftpRemoteFileTemplate.execute(session -> {
- boolean existFile = session.exists(fileFullPath);
- if (existFile) {
- return session.remove(fileFullPath);
- } else {
- log.info("Cannot delete SFTP server's file. Caused by: file does not exist, full path: {} ",
- fileFullPath);
- return false;
- }
- });
- }
-}
diff --git a/api-portal/src/main/resources/application-development-docker.yml b/api-portal/src/main/resources/application-development-docker.yml
deleted file mode 100644
index 674eae8a..00000000
--- a/api-portal/src/main/resources/application-development-docker.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-eureka:
- client:
- serviceUrl:
- defaultZone: http://maf.service-registry.dev:8760/eureka/
-
-spring:
- zipkin:
- base-url: http://maf.open-zipkin.dev:9411
- datasource:
- name: muscle_and_fitness
- driver-class-name: com.mysql.cj.jdbc.Driver
- type: com.alibaba.druid.pool.DruidDataSource
- url: jdbc:mysql://maf.mysql.dev:3306/muscle_and_fitness?useSSL=true&useUnicode=true
- username: root
- password: jm@mysql
- redis:
- database: 0
- host: maf.redis.dev
- port: 6379
- password: 123456
- timeout: 10000ms
- lettuce:
- pool:
- max-active: 20
- max-idle: 10
- max-wait: -1ms
- min-idle: 0
-
-logging:
- # Configure logging level for SFTP/JSCH
- level:
- com.jcraft.jsch: INFO
-
-custom:
- configuration:
- super-user: "admin"
- # Make `web-security-disabled` equal to true to disable web security. We suggest you do not turn off web security
- # feature unless development environment.
- web-security-disabled: false
- # Disable web request information log
- web-request-log-disabled: false
- ignored-request:
- post:
- - "/authentication/**"
- get:
- - "/auth/check-username-uniqueness"
- - "/auth/check-email-uniqueness"
- - "/auth/validate-username/**"
- - "/user/get-avatar"
- - "/common/get-jwt"
- pattern:
- - "/actuator/**"
- - "/druid/**"
- - "/swagger-resources/**"
- - "/v2/api-docs/**"
-
-sftp:
- client:
- configuration:
- host: maf.atmoz-sftp.dev
- port: 22
- user: johnny
- password: atmoz@sftp
- directory: upload
- private-key:
- private-key-pass-phrase:
- session-cache-size: 20
- session-wait-timeout: 15000
diff --git a/api-portal/src/main/resources/application-development-local.yml b/api-portal/src/main/resources/application-development-local.yml
deleted file mode 100644
index fff002a0..00000000
--- a/api-portal/src/main/resources/application-development-local.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-eureka:
- client:
- serviceUrl:
- defaultZone: http://localhost:8760/eureka/
-
-spring:
- zipkin:
- base-url: http://localhost:9411
- datasource:
- name: muscle_and_fitness
- driver-class-name: com.mysql.cj.jdbc.Driver
- type: com.alibaba.druid.pool.DruidDataSource
- url: jdbc:mysql://localhost:3306/muscle_and_fitness?useSSL=true&useUnicode=true
- username: root
- password: jm@mysql
- devtools:
- restart:
- enabled: true
- redis:
- database: 0
- host: localhost
- port: 6379
- password: 123456
- timeout: 10000ms
- lettuce:
- pool:
- max-active: 20
- max-idle: 10
- max-wait: -1ms
- min-idle: 0
-
-logging:
- # Configure logging level for SFTP/JSCH
- level:
- com.jcraft.jsch: INFO
-
-custom:
- configuration:
- super-user: "admin"
- # Make `web-security-disabled` equal to true to disable web security. We suggest you do not turn off web security
- # feature unless development environment.
- web-security-disabled: false
- # Disable web request information log
- web-request-log-disabled: false
- ignored-request:
- post:
- - "/authentication/**"
- get:
- - "/auth/check-username-uniqueness"
- - "/auth/check-email-uniqueness"
- - "/auth/validate-username/**"
- - "/user/get-avatar"
- - "/common/get-jwt"
- pattern:
- - "/actuator/**"
- - "/druid/**"
- - "/swagger-resources/**"
- - "/v2/api-docs/**"
-
-sftp:
- client:
- configuration:
- host: localhost
- port: 23
- user: johnny
- password: atmoz@sftp
- directory: upload
- private-key:
- private-key-pass-phrase:
- session-cache-size: 20
- session-wait-timeout: 15000
diff --git a/api-portal/src/main/resources/application-production.yml b/api-portal/src/main/resources/application-production.yml
deleted file mode 100644
index 989017fa..00000000
--- a/api-portal/src/main/resources/application-production.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-eureka:
- client:
- serviceUrl:
- defaultZone: http://172.16.4.20:8760/eureka/
-
-spring:
- zipkin:
- base-url: http://172.16.4.13:9411
- datasource:
- name: muscle_and_fitness
- driver-class-name: com.mysql.cj.jdbc.Driver
- type: com.alibaba.druid.pool.DruidDataSource
- url: jdbc:mysql://172.16.4.10:3306/muscle_and_fitness?useSSL=true&useUnicode=true
- username: root
- password: jm@mysql
- redis:
- database: 0
- host: 172.16.4.11
- port: 6379
- password: 123456
- timeout: 10000ms
- lettuce:
- pool:
- max-active: 20
- max-idle: 10
- max-wait: -1ms
- min-idle: 0
-
-logging:
- # Configure logging level for SFTP/JSCH
- level:
- com.jcraft.jsch: INFO
-
-custom:
- configuration:
- super-user: "admin"
- # Make `web-security-disabled` equal to true to disable web security. We suggest you do not turn off web security
- # feature unless development environment.
- web-security-disabled: false
- # Disable web request information log
- web-request-log-disabled: false
- ignored-request:
- post:
- - "/authentication/**"
- get:
- - "/auth/check-username-uniqueness"
- - "/auth/check-email-uniqueness"
- - "/auth/validate-username/**"
- - "/user/get-avatar"
- - "/common/get-jwt"
- pattern:
- - "/actuator/**"
- - "/druid/**"
- - "/swagger-resources/**"
- - "/v2/api-docs/**"
-
-sftp:
- client:
- configuration:
- host: 172.16.4.12
- port: 22
- user: johnny
- password: atmoz@sftp
- directory: upload
- private-key:
- private-key-pass-phrase:
- session-cache-size: 20
- session-wait-timeout: 15000
diff --git a/api-portal/src/main/resources/application-stage.yml b/api-portal/src/main/resources/application-stage.yml
deleted file mode 100644
index 423d2ebd..00000000
--- a/api-portal/src/main/resources/application-stage.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-eureka:
- client:
- serviceUrl:
- defaultZone: http://172.16.3.20:8760/eureka/
-
-spring:
- zipkin:
- base-url: http://172.16.3.13:9411
- datasource:
- name: muscle_and_fitness
- driver-class-name: com.mysql.cj.jdbc.Driver
- type: com.alibaba.druid.pool.DruidDataSource
- url: jdbc:mysql://172.16.4.10:3306/muscle_and_fitness?useSSL=true&useUnicode=true
- username: root
- password: jm@mysql
- redis:
- database: 0
- host: 172.16.3.11
- port: 6379
- password: 123456
- timeout: 10000ms
- lettuce:
- pool:
- max-active: 20
- max-idle: 10
- max-wait: -1ms
- min-idle: 0
-
-logging:
- # Configure logging level for SFTP/JSCH
- level:
- com.jcraft.jsch: INFO
-
-custom:
- configuration:
- super-user: "admin"
- # Make `web-security-disabled` equal to true to disable web security. We suggest you do not turn off web security
- # feature unless development environment.
- web-security-disabled: false
- # Disable web request information log
- web-request-log-disabled: false
- ignored-request:
- post:
- - "/authentication/**"
- get:
- - "/auth/check-username-uniqueness"
- - "/auth/check-email-uniqueness"
- - "/auth/validate-username/**"
- - "/user/get-avatar"
- - "/common/get-jwt"
- pattern:
- - "/actuator/**"
- - "/druid/**"
- - "/swagger-resources/**"
- - "/v2/api-docs/**"
-
-sftp:
- client:
- configuration:
- host: 172.16.3.12
- port: 22
- user: johnny
- password: atmoz@sftp
- directory: upload
- private-key:
- private-key-pass-phrase:
- session-cache-size: 20
- session-wait-timeout: 15000
diff --git a/api-portal/src/main/resources/application-test.yml b/api-portal/src/main/resources/application-test.yml
deleted file mode 100644
index 36c7664c..00000000
--- a/api-portal/src/main/resources/application-test.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-eureka:
- client:
- serviceUrl:
- defaultZone: http://172.16.2.20:8760/eureka/
-
-spring:
- zipkin:
- base-url: http://172.16.2.13:9411
- datasource:
- name: muscle_and_fitness
- driver-class-name: com.mysql.cj.jdbc.Driver
- type: com.alibaba.druid.pool.DruidDataSource
- url: jdbc:mysql://172.16.2.10:3306/muscle_and_fitness?useSSL=true&useUnicode=true
- username: root
- password: jm@mysql
- redis:
- database: 0
- host: 172.16.2.11
- port: 6379
- password: 123456
- timeout: 10000ms
- lettuce:
- pool:
- max-active: 20
- max-idle: 10
- max-wait: -1ms
- min-idle: 0
-
-logging:
- # Configure logging level for SFTP/JSCH
- level:
- com.jcraft.jsch: INFO
-
-custom:
- configuration:
- super-user: "admin"
- # Make `web-security-disabled` equal to true to disable web security. We suggest you do not turn off web security
- # feature unless development environment.
- web-security-disabled: false
- # Disable web request information log
- web-request-log-disabled: false
- ignored-request:
- post:
- - "/authentication/**"
- get:
- - "/auth/check-username-uniqueness"
- - "/auth/check-email-uniqueness"
- - "/auth/validate-username/**"
- - "/user/get-avatar"
- - "/common/get-jwt"
- pattern:
- - "/actuator/**"
- - "/druid/**"
- - "/swagger-resources/**"
- - "/v2/api-docs/**"
-
-sftp:
- client:
- configuration:
- host: 172.16.2.12
- port: 22
- user: johnny
- password: atmoz@sftp
- directory: upload
- private-key:
- private-key-pass-phrase:
- session-cache-size: 20
- session-wait-timeout: 15000
diff --git a/api-portal/src/main/resources/application.yml b/api-portal/src/main/resources/application.yml
deleted file mode 100644
index 106b7359..00000000
--- a/api-portal/src/main/resources/application.yml
+++ /dev/null
@@ -1,108 +0,0 @@
-server:
- port: @api-portal.port@
- tomcat:
- uri-encoding: @project.build.sourceEncoding@
-
-spring:
- application:
- name: @project.artifactId@
- profiles:
- active: @env@
- mvc:
- throw-exception-if-no-handler-found: true
- jackson:
- date-format: yyyy-MM-dd HH:mm:ss
- time-zone: Asia/Hong_Kong
- sleuth:
- sampler:
- probability: 1.0
- servlet:
- multipart:
- # `location` specifies the directory where uploaded files will be stored. When not specified,
- # a temporary directory will be used. ATTENTION: it may differ due to OS.
- location: /Users/johnny/Documents/@project.artifactId@/temprary-file
- # `max-file-size` specifies the maximum size permitted for uploaded files. The default is 1MB. We set it as 64 MB.
- max-file-size: 64MB
- # `max-request-size` specifies the maximum size allowed for multipart/form-data requests. The default is 10MB.
- max-request-size: 70MB
- # `file-size-threshold` specifies the size threshold after which files will be written to disk.
- # The default is 0. We set it as 0 too.
- file-size-threshold: 0
-
-eureka:
- instance:
- leaseRenewalIntervalInSeconds: 10
- health-check-url-path: /actuator/health
- status-page-url-path: /
- metadata-map:
- # needed to trigger info and endpoint update after restart
- startup: ${random.int}
- instance-id: ${spring.cloud.client.ip-address}:${server.port}@${spring.cloud.client.hostname}@${spring.application.name}-${random.int}
- prefer-ip-address: true
- client:
- registryFetchIntervalSeconds: 5
-
-feign:
- client:
- config:
- default:
- connectTimeout: 5000
- readTimeout: 10000
- loggerLevel: full
- compression:
- request:
- enabled: true
- response:
- enabled: true
- useGzipDecoder: true
-
-management:
- endpoints:
- web:
- exposure:
- include: "*"
- endpoint:
- health:
- show-details: ALWAYS
-
-mybatis-plus:
- configuration:
- map-underscore-to-camel-case: true
- log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
- # mapper-locations should start with `classpath*` prefix
- # when project is based on Maven multi-module to load XML mapper in different jar
- mapper-locations: classpath*:/mapper/**/*Mapper.xml
-
-logging:
- config: classpath:configuration/logback/logback-@env@.xml
- # Configure logging level of project as DEBUG to enable SQL logging and other logging.
- level:
- com.jmsoftware: DEBUG
-
-project:
- property:
- base-package: com.jmsoftware.maf.maf.apiportal
- context-path:
- group-id: @project.groupId@
- project-parent-artifact-id: @project.parent.artifactId@
- project-artifact-id: @project.artifactId@
- version: @project.version@
- description: @project.description@
- jdk-version: @java.version@
- environment: @env@
- url: @project.url@
- inception-year: @inceptionYear@
- organization-name: @project.organization.name@
- organization-url: @project.organization.url@
- issue-management-system: @project.issueManagement.system@
- issue-management-url: @project.issueManagement.url@
- developer-name: @developerName@
- developer-email: @developerEmail@
- developer-url: @developerUrl@
-
-# Customize JWT configuration for development environment.
-jwt:
- configuration:
- # an hour
- ttl: 3600000
- ttl-for-remember-me: 604800000
diff --git a/api-portal/src/main/resources/configuration/.empty b/api-portal/src/main/resources/configuration/.empty
deleted file mode 100644
index e69de29b..00000000
diff --git a/api-portal/src/main/resources/static/script/home.js b/api-portal/src/main/resources/static/script/home.js
deleted file mode 100644
index a191d8c5..00000000
--- a/api-portal/src/main/resources/static/script/home.js
+++ /dev/null
@@ -1,72 +0,0 @@
-// noinspection JSUnusedGlobalSymbols
-const vm = new Vue({
- el: '#app',
- data: {
- projectArtifactId: null,
- version: null,
- applicationName: null,
- newPerson: {
- name: '',
- age: 0,
- sex: 'Male'
- },
- people: [{
- name: 'Jack',
- age: 30,
- sex: 'Male'
- }, {
- name: 'Bill',
- age: 26,
- sex: 'Male'
- }, {
- name: 'Tracy',
- age: 22,
- sex: 'Female'
- }, {
- name: 'Chris',
- age: 36,
- sex: 'Male'
- }]
- },
- methods: {
- /**
- * Create a person
- */
- createPerson: function () {
- this.people.push(this.newPerson);
- this.newPerson = {name: '', age: 0, sex: 'Male'}
-
- },
- /**
- * delete a person
- * @param index
- */
- deletePerson: function (index) {
- this.people.splice(index, 1);
- },
- handleClickSwaggerApiDocumentation: function () {
- const currentUrl = window.location.href;
- const split = currentUrl.split('/');
- window.location.href = `${split[0]}//${split[2]}/doc`;
- },
- handleClickVideoDemo: function () {
- const currentUrl = window.location.href;
- const split = currentUrl.split('/');
- window.location.href = `${split[0]}//${split[2]}/${split[3]}/video.html`;
- },
- getAppInfo: async function () {
- const currentUrl = window.location.href;
- const split = currentUrl.split('/');
- const baseUrl = `${split[0]}//${split[2]}`;
- const response = await fetch(`${baseUrl}/common/app-info`);
- const responseJson = await response.json();
- this.projectArtifactId = responseJson.data.projectArtifactId;
- this.version = responseJson.data.version;
- this.applicationName = this.projectArtifactId.toUpperCase();
- window.document.title = this.applicationName;
- }
- },
- mounted: async function () {
- this.getAppInfo();
- }
-});
diff --git a/api-portal/src/test/java/com/jmsoftware/maf/apiportal/ApiPortalApplicationTests.java b/api-portal/src/test/java/com/jmsoftware/maf/apiportal/ApiPortalApplicationTests.java
deleted file mode 100644
index 202e1338..00000000
--- a/api-portal/src/test/java/com/jmsoftware/maf/apiportal/ApiPortalApplicationTests.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.jmsoftware.maf.apiportal;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class ApiPortalApplicationTests {
-
- @Test
- void contextLoads() {
- }
-
-}
diff --git a/auth-center/auto-run-windows.cmd b/auth-center/auto-run-windows.cmd
index cd3242c5..2b4a7fc1 100644
--- a/auth-center/auto-run-windows.cmd
+++ b/auth-center/auto-run-windows.cmd
@@ -16,8 +16,10 @@ chcp 65001
@REM #################### Configurable Environment Variables ###################
SET skipGitPull=true
SET skipMavenBuild=true
+SET minimalJavaMajorVersion=11
+SET javaExe=C:\Users\Johnny\.sdkman\candidates\java\11.0.10.hs-adpt\bin\java.exe
SET mavenActiveProfile="development-local"
-SET javaParameter=-Dfile.encoding=UTF-8 -Xms256m -Xmx256m
+SET javaParameter=-Xms256m -Xmx256m -Dfile.encoding=UTF-8 -Dspring.cloud.consul.host=localhost
GOTO:MAIN
@@ -55,6 +57,22 @@ EXIT /B 0
@REM ############################ Custom Functions #############################
+@REM Check Java major version
+:checkJavaMajorVersion
+CALL :logWarn "Start to Check Java major version…"
+%javaExe% -version 1>nul 2>nul || (
+ CALL :logError "Java is not installed!"
+ EXIT /B 2
+)
+for /f tokens^=2-6^ delims^=.-_+^" %%j in ('%javaExe% -fullversion 2^>^&1') do set "currentJavaMajorVersion=%%j"
+CALL :logWarn "Got current Java major version number: %currentJavaMajorVersion%"
+if %currentJavaMajorVersion% LSS %minimalJavaMajorVersion% (
+ CALL :logError "Current Java version is too low, at least OpenJDK %minimalJavaMajorVersion% is needed"
+ EXIT /B 1
+)
+CALL :logInfo "Passed Java major version cheking"
+EXIT /B 0
+
@REM Pull the latest code of current branch from Git.
:gitPull
git pull
@@ -76,7 +94,7 @@ EXIT /B 0
CALL :gitPull
)
CALL :logInfo "[PRE-BUILD] Java Version Information"
- CALL java -version
+ CALL %javaExe% -version
CALL :logInfo "[PRE-BUILD] Maven Version Information"
CALL mvn -v
CALL :logInfo "[PRE-BUILD] Current directory:"
@@ -113,7 +131,7 @@ EXIT /B 0
)
CALL :logWarn "[RUN] Found JAR: %jarFileName%"
CALL :setTerminalTitle %jarFileName%
- SET runJarCommand=java %javaParameter% -Dspring.profiles.active=%mavenActiveProfile% -jar target\%jarFileName%
+ SET runJarCommand=%javaExe% %javaParameter% -Dspring.profiles.active=%mavenActiveProfile% -jar target\%jarFileName%
CALL :logWarn "[RUN] Execute command: %runJarCommand%"
CALL %runJarCommand%
EXIT /B 0
@@ -121,6 +139,14 @@ EXIT /B 0
@REM ############################# MAIN Procedures #############################
:MAIN
cls
+
+@REM Check Java major version
+CALL :checkJavaMajorVersion
+if %ERRORLEVEL% NEQ 0 (
+ CALL :logError "Failed to check Java major version!"
+ EXIT /B %ERRORLEVEL%
+)
+
@REM Pre-build phrase (Display version, Git pull)
CALL :executePreBuildPhase
if %ERRORLEVEL% NEQ 0 (
diff --git a/auth-center/pom.xml b/auth-center/pom.xml
index 3bf21d4c..a859a01c 100644
--- a/auth-center/pom.xml
+++ b/auth-center/pom.xml
@@ -1,5 +1,5 @@
-
4.0.0
@@ -10,7 +10,7 @@
com.jmsoftware.maf
muscle-and-fitness-server
- 0.0.1
+ 0.0.2
@@ -19,22 +19,31 @@
org.springframework.boot
spring-boot-maven-plugin
+
+
+ build-info
+ compile
+
+ build-info
+
+
+
com.google.cloud.tools
jib-maven-plugin
- 2.2.0
+ ${jib-maven-plugin.version}
-
+
buildAndPushDockerImagePhase
@@ -46,8 +55,8 @@
-
- openjdk:11.0.9.1-jre-slim
+
+ adoptopenjdk/openjdk11:${adoptopenjdk11.tag}
docker.io/ijohnnymiller/${project.parent.artifactId}.${project.artifactId}
@@ -73,85 +82,58 @@
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.springframework.cloud
- spring-cloud-starter-netflix-eureka-client
-
-
- de.codecentric
- spring-boot-admin-starter-client
- ${spring-boot-admin.version}
-
-
- org.springframework.cloud
- spring-cloud-starter-zipkin
-
-
- org.springframework.boot
- spring-boot-starter-security
-
-
- org.springframework.boot
- spring-boot-starter-data-redis
-
-
- org.springframework.integration
- spring-integration-sftp
-
-
-
- com.jmsoftware.maf
- common
-
com.jmsoftware.maf
- muscle-and-fitness-server-spring-boot-starter
-
-
-
-
- com.baomidou
- mybatis-plus-boot-starter
- 3.3.1
-
-
- mysql
- mysql-connector-java
- runtime
-
-
- com.alibaba
- druid
- 1.1.22
-
-
-
- redis.clients
- jedis
+ spring-cloud-starter
+
+
+ org.springframework.integration
+ spring-integration-sftp
+
+
+ io.minio
+ minio
+
+
+
io.jsonwebtoken
jjwt-api
- 0.11.1
+ ${jjwt.version}
io.jsonwebtoken
jjwt-impl
- 0.11.1
+ ${jjwt.version}
runtime
io.jsonwebtoken
jjwt-jackson
- 0.11.1
+ ${jjwt.version}
runtime
+
+
+ com.jmsoftware.maf
+ universal-ui
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.java
index 927d2001..b6bead0d 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.java
@@ -1,24 +1,19 @@
package com.jmsoftware.maf.authcenter;
-import com.jmsoftware.maf.authcenter.universal.configuration.ProjectProperty;
-import com.jmsoftware.maf.authcenter.universal.configuration.ServerConfiguration;
+import com.jmsoftware.maf.springcloudstarter.helper.SpringBootStartupHelper;
import lombok.extern.slf4j.Slf4j;
-import lombok.val;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.TimeZone;
+import org.springframework.util.StopWatch;
/**
* AuthCenterApplication
*
* Change description here.
*
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
* @date 3/12/20 9:57 AM
**/
@Slf4j
@@ -26,27 +21,16 @@
@EnableDiscoveryClient
@SpringBootApplication
public class AuthCenterApplication {
- private static final String LINE_SEPARATOR = System.lineSeparator();
- private static ProjectProperty projectProperty;
- private static ServerConfiguration serverConfiguration;
+ private static final StopWatch STOP_WATCH = new StopWatch();
+ private static SpringBootStartupHelper springBootStartupHelper;
- public AuthCenterApplication(ProjectProperty projectProperty, ServerConfiguration serverConfiguration) {
- AuthCenterApplication.projectProperty = projectProperty;
- AuthCenterApplication.serverConfiguration = serverConfiguration;
+ public AuthCenterApplication(SpringBootStartupHelper springBootStartupHelper) {
+ AuthCenterApplication.springBootStartupHelper = springBootStartupHelper;
}
public static void main(String[] args) {
- val startInstant = Instant.now();
+ STOP_WATCH.start();
SpringApplication.run(AuthCenterApplication.class, args);
- val endInstant = Instant.now();
- val duration = Duration.between(startInstant, endInstant);
- log.info("🥳 Congratulations! 🎉");
- log.info("🖥 {}@{} started!", projectProperty.getProjectArtifactId(), projectProperty.getVersion());
- log.info("⚙️ Environment: {}", projectProperty.getEnvironment());
- log.info("⏳ Deployment duration: {} seconds ({} ms)", duration.getSeconds(), duration.toMillis());
- log.info("⏰ App started at {} (timezone - {})", endInstant, TimeZone.getDefault().getDisplayName());
- log.info("{} App running at{} - Local: http://localhost:{}{}/{} - Network: {}/",
- LINE_SEPARATOR, LINE_SEPARATOR, serverConfiguration.getServerPort(), projectProperty.getContextPath(),
- LINE_SEPARATOR, serverConfiguration.getBaseUrl());
+ springBootStartupHelper.stop(STOP_WATCH);
}
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.java
new file mode 100644
index 00000000..73567962
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.java
@@ -0,0 +1,27 @@
+package com.jmsoftware.maf.authcenter.permission.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import java.util.Set;
+
+/**
+ * Description: PermissionConfiguration, change description here.
+ *
+ * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 2/8/2021 5:18 PM
+ **/
+@Data
+@Validated
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = PermissionConfiguration.PREFIX)
+public class PermissionConfiguration {
+ public static final String PREFIX = "maf.configuration.permission";
+ @NotEmpty
+ private Set<@NotBlank String> ignoredServiceIds;
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/controller/PermissionController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/controller/PermissionController.java
index 6c98c62f..657ceabc 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/controller/PermissionController.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/controller/PermissionController.java
@@ -1,29 +1,42 @@
package com.jmsoftware.maf.authcenter.permission.controller;
-import com.jmsoftware.maf.authcenter.permission.entity.PermissionPersistence;
+import com.jmsoftware.maf.authcenter.permission.entity.GetServicesInfoResponse;
import com.jmsoftware.maf.authcenter.permission.service.PermissionService;
+import com.jmsoftware.maf.common.bean.ResponseBodyBean;
+import com.jmsoftware.maf.common.exception.BusinessException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import javax.annotation.Resource;
-
- /**
+/**
*
PermissionController
*
* Controller implementation of Permission.(Permission)
*
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
* @date 5/11/20 8:34 AM
*/
+@Slf4j
@RestController
-@RequestMapping("permission")
+@RequiredArgsConstructor
+@Api(tags = {"Permission API"})
public class PermissionController {
- @Resource
- private PermissionService permissionService;
+ private final PermissionService permissionService;
- @GetMapping("selectOne")
- public PermissionPersistence selectOne(Long id) {
- return this.permissionService.queryById(id);
+ /**
+ * Services info response body bean.
+ *
+ * @return the response body bean
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/25/2020 5:44 PM
+ * @see
+ * RestTemplate Excample
+ */
+ @GetMapping("/permissions/services-info")
+ @ApiOperation(value = "Get services info", notes = "Get services info")
+ public ResponseBodyBean getServicesInfo() throws BusinessException {
+ return ResponseBodyBean.ofSuccess(permissionService.getServicesInfo());
}
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/remote/PermissionRemoteApiController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/controller/PermissionRemoteApiController.java
similarity index 51%
rename from auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/remote/PermissionRemoteApiController.java
rename to auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/controller/PermissionRemoteApiController.java
index c6cc344d..b1a7fcc2 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/remote/PermissionRemoteApiController.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/controller/PermissionRemoteApiController.java
@@ -1,16 +1,13 @@
-package com.jmsoftware.maf.authcenter.permission.remote;
+package com.jmsoftware.maf.authcenter.permission.controller;
import com.jmsoftware.maf.authcenter.permission.service.PermissionService;
import com.jmsoftware.maf.common.bean.ResponseBodyBean;
import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -21,25 +18,19 @@
*
* Change description here.
*
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
* @date 5/11/20 8:24 AM
**/
@RestController
@RequiredArgsConstructor
@RequestMapping("/permission-remote-api")
-@Api(tags = {"Permission Remote API Controller"})
+@Api(tags = {"Permission Remote API"})
public class PermissionRemoteApiController {
private final PermissionService permissionService;
- @PostMapping("/get-permission-list-by-role-id-list")
- @ApiOperation(value = "Get permission list by role id list", notes = "GGet permission list by role id list")
- public ResponseBodyBean getPermissionListByRoleIdList(@Valid @RequestBody GetPermissionListByRoleIdListPayload payload) {
+ @GetMapping("/permissions")
+ @ApiOperation(value = "Get permission list by role id list", notes = "Get permission list by role id list (remote)")
+ public ResponseBodyBean getPermissionListByRoleIdList(@Valid GetPermissionListByRoleIdListPayload payload) {
return ResponseBodyBean.ofSuccess(permissionService.getPermissionListByRoleIdList(payload));
}
-
- @PostMapping("/get-permission-list-by-user-id")
- @ApiOperation(value = "Get permission list by user id", notes = "Get permission list by user id")
- public ResponseBodyBean getPermissionListByUserId(@Valid @RequestBody GetPermissionListByUserIdPayload payload) {
- return ResponseBodyBean.ofSuccess(permissionService.getPermissionListByUserId(payload));
- }
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/GetServicesInfoResponse.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/GetServicesInfoResponse.java
new file mode 100644
index 00000000..ba8807a3
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/GetServicesInfoResponse.java
@@ -0,0 +1,23 @@
+package com.jmsoftware.maf.authcenter.permission.entity;
+
+import com.google.common.collect.Lists;
+import com.jmsoftware.maf.common.domain.springbootstarter.HttpApiResourcesResponse;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Description: GetServicesInfoResponse, change description here.
+ *
+ * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/28/2020 9:30 AM
+ **/
+@Data
+public class GetServicesInfoResponse {
+ private List list = Lists.newLinkedList();
+
+ @Data
+ public static class ServiceInfo{
+ private String serviceId;
+ private HttpApiResourcesResponse httpApiResources;
+ }
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/PermissionPersistence.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/PermissionPersistence.java
deleted file mode 100644
index 2a1da16d..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/PermissionPersistence.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission.entity;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * Permission.(Permission) Persistence object class
- *
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
- * @date 5/11/20 8:34 AM
- */
-@Data
-public class PermissionPersistence implements Serializable {
- private static final long serialVersionUID = -56601096713236790L;
- /**
- * Primary key
- */
- private Long id;
- /**
- * URL. If type of record is page (1), URL stands for route; if type of record is button (2), URL stands for API
- */
- private String url;
- /**
- * Permission description
- */
- private String description;
- /**
- * Permission type. 1 - page; 2 - button
- */
- private Integer type;
- /**
- * Permission expression
- */
- private String permissionExpression;
- /**
- * HTTP method of API
- */
- private String method;
- /**
- * Sort number
- */
- private Integer sort;
- /**
- * Primary key of parent
- */
- private Long parentId;
- /**
- * Deleted flag
- */
- private Integer deleted;
- /**
- * Created time
- */
- private Date createdTime;
- /**
- * Modified time
- */
- private Date modifiedTime;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/persistence/Permission.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/persistence/Permission.java
new file mode 100644
index 00000000..0bb7187a
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/entity/persistence/Permission.java
@@ -0,0 +1,129 @@
+package com.jmsoftware.maf.authcenter.permission.entity.persistence;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+import static com.baomidou.mybatisplus.annotation.FieldFill.INSERT;
+import static com.baomidou.mybatisplus.annotation.FieldFill.UPDATE;
+
+/**
+ * Permission
+ *
+ * Permission Persistence object class
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 3:22 PM
+ */
+@Data
+@TableName(value = Permission.TABLE_NAME)
+public class Permission {
+ /**
+ * Primary key
+ */
+ @TableId(value = COL_ID, type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * URL. If type of record is page (1), URL stands for route; if type of record is button (2), URL stands for API
+ */
+ @TableField(value = COL_URL)
+ private String url;
+
+ /**
+ * Permission description
+ */
+ @TableField(value = COL_DESCRIPTION)
+ private String description;
+
+ /**
+ * Permission type. 1 - page; 2 - button
+ */
+ @TableField(value = COL_TYPE)
+ private Byte type;
+
+ /**
+ * Permission expression
+ */
+ @TableField(value = COL_PERMISSION_EXPRESSION)
+ private String permissionExpression;
+
+ /**
+ * HTTP method of API
+ */
+ @TableField(value = COL_METHOD)
+ private Object method;
+
+ /**
+ * Sort number
+ */
+ @TableField(value = COL_SORT)
+ private Integer sort;
+
+ /**
+ * Primary key of parent
+ */
+ @TableField(value = COL_PARENT_ID)
+ private Long parentId;
+
+ /**
+ * Created by
+ */
+ @TableField(value = COL_CREATED_BY, fill = INSERT)
+ private Long createdBy;
+
+ /**
+ * Created time
+ */
+ @TableField(value = COL_CREATED_TIME, fill = INSERT)
+ private Date createdTime;
+
+ /**
+ * Modified by
+ */
+ @TableField(value = COL_MODIFIED_BY, fill = UPDATE)
+ private Long modifiedBy;
+
+ /**
+ * Modified time
+ */
+ @TableField(value = COL_MODIFIED_TIME, fill = UPDATE)
+ private Date modifiedTime;
+
+ /**
+ * Deleted flag
+ */
+ @TableField(value = COL_DELETED, fill = INSERT)
+ private Byte deleted;
+
+ public static final String TABLE_NAME = "permission";
+
+ public static final String COL_ID = "id";
+
+ public static final String COL_URL = "url";
+
+ public static final String COL_DESCRIPTION = "description";
+
+ public static final String COL_TYPE = "type";
+
+ public static final String COL_PERMISSION_EXPRESSION = "permission_expression";
+
+ public static final String COL_METHOD = "method";
+
+ public static final String COL_SORT = "sort";
+
+ public static final String COL_PARENT_ID = "parent_id";
+
+ public static final String COL_CREATED_BY = "created_by";
+
+ public static final String COL_CREATED_TIME = "created_time";
+
+ public static final String COL_MODIFIED_BY = "modified_by";
+
+ public static final String COL_MODIFIED_TIME = "modified_time";
+
+ public static final String COL_DELETED = "deleted";
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.java
index 953704d2..bc31588f 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.java
@@ -1,6 +1,8 @@
package com.jmsoftware.maf.authcenter.permission.mapper;
-import com.jmsoftware.maf.authcenter.permission.entity.PermissionPersistence;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jmsoftware.maf.authcenter.permission.entity.persistence.Permission;
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -11,73 +13,18 @@
*
* Mapper of Permission.(Permission)
*
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
* @date 5 /11/20 8:34 AM
*/
@Mapper
-public interface PermissionMapper {
- /**
- * Query by id permission persistence.
- *
- * @param id the id
- * @return the permission persistence
- */
- PermissionPersistence queryById(Long id);
-
- /**
- * Query all by limit list.
- *
- * @param offset the offset
- * @param limit the limit
- * @return the list
- */
- List queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);
-
- /**
- * Query all list.
- *
- * @param permissionPersistence the permission persistence
- * @return the list
- */
- List queryAll(PermissionPersistence permissionPersistence);
-
- /**
- * Insert int.
- *
- * @param permissionPersistence the permission persistence
- * @return the int
- */
- int insert(PermissionPersistence permissionPersistence);
-
- /**
- * Update int.
- *
- * @param permissionPersistence the permission persistence
- * @return the int
- */
- int update(PermissionPersistence permissionPersistence);
-
- /**
- * Delete by id int.
- *
- * @param id the id
- * @return the int
- */
- int deleteById(Long id);
-
+public interface PermissionMapper extends BaseMapper {
/**
* Select permission list by role id list list.
*
- * @param roleIdList the role id list
- * @return the list
- */
- List selectPermissionListByRoleIdList(List roleIdList);
-
- /**
- * Select permission list by user id list.
- *
- * @param userId the user id
+ * @param roleIdList the role id list
+ * @param permissionTypeList the permission type list
* @return the list
*/
- List selectPermissionListByUserId(Long userId);
+ List selectPermissionListByRoleIdList(@Param("roleIdList") List roleIdList,
+ @Param("permissionTypeList") List permissionTypeList);
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.java
index 9e8d2c89..1ef58523 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.java
@@ -1,14 +1,16 @@
package com.jmsoftware.maf.authcenter.permission.service;
-import com.jmsoftware.maf.authcenter.permission.entity.PermissionPersistence;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jmsoftware.maf.authcenter.permission.entity.GetServicesInfoResponse;
+import com.jmsoftware.maf.authcenter.permission.entity.persistence.Permission;
import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdResponse;
-import lombok.NonNull;
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
+import com.jmsoftware.maf.common.exception.BusinessException;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
@@ -16,52 +18,11 @@
*
* Service of Permission.(Permission)
*
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
* @date 5 /11/20 8:34 AM
*/
@Validated
-public interface PermissionService {
- /**
- * Query by ID
- *
- * @param id the primary key ID
- * @return the entity
- */
- PermissionPersistence queryById(Long id);
-
- /**
- * Query all by limit
- *
- * @param offset the offset
- * @param limit the limit
- * @return the entity list
- */
- List queryAllByLimit(int offset, int limit);
-
- /**
- * Insert
- *
- * @param permissionPersistence the entity
- * @return the entity
- */
- PermissionPersistence insert(PermissionPersistence permissionPersistence);
-
- /**
- * Update
- *
- * @param permissionPersistence the entity
- * @return the entity
- */
- PermissionPersistence update(PermissionPersistence permissionPersistence);
-
- /**
- * Delete by ID
- *
- * @param id the primary key ID
- * @return the boolean
- */
- boolean deleteById(Long id);
-
+public interface PermissionService extends IService {
/**
* Gets permission list by role id list.
*
@@ -73,24 +34,18 @@ public interface PermissionService {
/**
* Gets permission list by role id list.
*
- * @param roleIdList the role id list
+ * @param roleIdList the role id list
+ * @param permissionTypeList the permission type list
* @return the permission list by role id list
*/
- List getPermissionListByRoleIdList(@NonNull List roleIdList);
-
- /**
- * Gets permission list by user id.
- *
- * @param payload the payload
- * @return the permission list by user id
- */
- GetPermissionListByUserIdResponse getPermissionListByUserId(@Valid GetPermissionListByUserIdPayload payload);
+ List getPermissionListByRoleIdList(@NotEmpty List roleIdList,
+ @NotEmpty List permissionTypeList);
/**
- * Gets permission list by user id.
+ * Gets services info.
*
- * @param userId the user id
- * @return the permission list by user id
+ * @return the services info
+ * @throws BusinessException the business exception
*/
- List getPermissionListByUserId(@NonNull Long userId);
+ GetServicesInfoResponse getServicesInfo() throws BusinessException;
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.java
index 16d4d206..efbdf77c 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.java
@@ -2,69 +2,67 @@
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
-import com.jmsoftware.maf.authcenter.permission.entity.PermissionPersistence;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.jmsoftware.maf.authcenter.permission.configuration.PermissionConfiguration;
+import com.jmsoftware.maf.authcenter.permission.entity.GetServicesInfoResponse;
+import com.jmsoftware.maf.authcenter.permission.entity.persistence.Permission;
import com.jmsoftware.maf.authcenter.permission.mapper.PermissionMapper;
import com.jmsoftware.maf.authcenter.permission.service.PermissionService;
+import com.jmsoftware.maf.authcenter.role.service.RoleService;
+import com.jmsoftware.maf.common.bean.ResponseBodyBean;
import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByUserIdResponse;
-import lombok.NonNull;
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
+import com.jmsoftware.maf.common.domain.springbootstarter.HttpApiResourcesResponse;
+import com.jmsoftware.maf.common.exception.BusinessException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import lombok.val;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
-import javax.annotation.Resource;
import javax.validation.Valid;
-import java.util.Collections;
+import javax.validation.constraints.NotEmpty;
import java.util.List;
+import java.util.Optional;
/**
* PermissionServiceImpl
*
* Service implementation of Permission.(Permission)
*
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
* @date 5/11/20 8:34 AM
*/
-@Service("permissionService")
-public class PermissionServiceImpl implements PermissionService {
- @Resource
- private PermissionMapper permissionMapper;
-
- @Override
- public PermissionPersistence queryById(Long id) {
- return this.permissionMapper.queryById(id);
- }
-
- @Override
- public List queryAllByLimit(int offset, int limit) {
- return this.permissionMapper.queryAllByLimit(offset, limit);
- }
-
- @Override
- public PermissionPersistence insert(PermissionPersistence permissionPersistence) {
- this.permissionMapper.insert(permissionPersistence);
- return permissionPersistence;
- }
-
- @Override
- public PermissionPersistence update(PermissionPersistence permissionPersistence) {
- this.permissionMapper.update(permissionPersistence);
- return this.queryById(permissionPersistence.getId());
- }
-
- @Override
- public boolean deleteById(Long id) {
- return this.permissionMapper.deleteById(id) > 0;
- }
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class PermissionServiceImpl extends ServiceImpl implements PermissionService {
+ private final RoleService roleService;
+ private final DiscoveryClient discoveryClient;
+ private final RestTemplate restTemplate;
+ private final PermissionConfiguration permissionConfiguration;
@Override
public GetPermissionListByRoleIdListResponse getPermissionListByRoleIdList(@Valid GetPermissionListByRoleIdListPayload payload) {
- val permissionList = this.getPermissionListByRoleIdList(payload.getRoleIdList());
+ val adminRole = roleService.checkAdmin(payload.getRoleIdList());
val response = new GetPermissionListByRoleIdListResponse();
+ if (adminRole) {
+ log.warn("Admin role checked. The role can access any resources");
+ val permission = new GetPermissionListByRoleIdListResponse.Permission();
+ permission.setUrl("/**");
+ permission.setType(PermissionType.BUTTON.getType());
+ permission.setPermissionExpression("admin-permission");
+ permission.setMethod("*");
+ response.getPermissionList().add(permission);
+ return response;
+ }
+ val permissionList = this.getPermissionListByRoleIdList(payload.getRoleIdList(),
+ payload.getPermissionTypeList());
permissionList.forEach(permissionPersistence -> {
- GetPermissionListByRoleIdListResponse.Permission permission =
- new GetPermissionListByRoleIdListResponse.Permission();
+ val permission = new GetPermissionListByRoleIdListResponse.Permission();
BeanUtil.copyProperties(permissionPersistence, permission);
response.getPermissionList().add(permission);
});
@@ -72,27 +70,37 @@ public GetPermissionListByRoleIdListResponse getPermissionListByRoleIdList(@Vali
}
@Override
- public List getPermissionListByRoleIdList(@NonNull List roleIdList) {
- if (CollUtil.isEmpty(roleIdList)) {
- return Collections.emptyList();
- }
- return permissionMapper.selectPermissionListByRoleIdList(roleIdList);
+ public List getPermissionListByRoleIdList(@NotEmpty List roleIdList,
+ @NotEmpty List permissionTypeList) {
+ return this.getBaseMapper().selectPermissionListByRoleIdList(roleIdList, permissionTypeList);
}
@Override
- public GetPermissionListByUserIdResponse getPermissionListByUserId(@Valid GetPermissionListByUserIdPayload payload) {
- val permissionList = this.getPermissionListByUserId(payload.getUserId());
- val response = new GetPermissionListByUserIdResponse();
- permissionList.forEach(permissionPersistence -> {
- val permission = new GetPermissionListByUserIdResponse.Permission();
- BeanUtil.copyProperties(permissionPersistence, permission);
- response.getPermissionList().add(permission);
- });
+ public GetServicesInfoResponse getServicesInfo() throws BusinessException {
+ val serviceIdList = discoveryClient.getServices();
+ log.info("Getting service info from Service ID list: {}", serviceIdList);
+ val response = new GetServicesInfoResponse();
+ val mapper = new ObjectMapper();
+ log.info("Ignored service ID: {}", permissionConfiguration.getIgnoredServiceIds());
+ for (String serviceId : serviceIdList) {
+ if (CollUtil.contains(permissionConfiguration.getIgnoredServiceIds(), serviceId)) {
+ log.warn("Ignored service ID: {}", serviceId);
+ continue;
+ }
+ ResponseBodyBean> responseBodyBean = Optional.ofNullable(restTemplate.getForObject(
+ String.format("http://%s/http-api-resources", serviceId), ResponseBodyBean.class))
+ .orElseThrow(() -> new BusinessException("Internal service mustn't respond null"));
+ val data = Optional.of(responseBodyBean.getData())
+ .orElseThrow(() -> new BusinessException("HttpApiResourcesResponse mustn't be null"));
+ val httpApiResourcesResponse = mapper.convertValue(data, HttpApiResourcesResponse.class);
+ val serviceInfo = new GetServicesInfoResponse.ServiceInfo();
+ serviceInfo.setServiceId(serviceId);
+ serviceInfo.setHttpApiResources(httpApiResourcesResponse);
+ response.getList().add(serviceInfo);
+ }
+ if (CollUtil.isEmpty(response.getList())) {
+ log.warn("Got am empty ServiceInfo list");
+ }
return response;
}
-
- @Override
- public List getPermissionListByUserId(@NonNull Long userId) {
- return permissionMapper.selectPermissionListByUserId(userId);
- }
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/controller/RoleController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/controller/RoleController.java
index 526472e6..9fd55e81 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/controller/RoleController.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/controller/RoleController.java
@@ -1,29 +1,16 @@
package com.jmsoftware.maf.authcenter.role.controller;
-import com.jmsoftware.maf.authcenter.role.entity.RolePersistence;
import com.jmsoftware.maf.authcenter.role.service.RoleService;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
+import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
-import javax.annotation.Resource;
-
- /**
- * RoleController
- *
- * Controller implementation of Role.(Role)
+/**
+ * Description: RoleController, change description here.
*
- * @author Johnny Miller (鍾俊)
- * @date 2020-05-10 22:39:51
- */
+ * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/17/2020 4:44 PM
+ **/
@RestController
-@RequestMapping("role")
+@RequiredArgsConstructor
public class RoleController {
- @Resource
- private RoleService roleService;
-
- @GetMapping("selectOne")
- public RolePersistence selectOne(Long id) {
- return this.roleService.queryById(id);
- }
+ private final RoleService roleService;
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/remote/RoleRemoteApiController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/controller/RoleRemoteApiController.java
similarity index 57%
rename from auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/remote/RoleRemoteApiController.java
rename to auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/controller/RoleRemoteApiController.java
index de0fed26..558c969f 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/remote/RoleRemoteApiController.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/controller/RoleRemoteApiController.java
@@ -1,37 +1,34 @@
-package com.jmsoftware.maf.authcenter.role.remote;
+package com.jmsoftware.maf.authcenter.role.controller;
import com.jmsoftware.maf.authcenter.role.service.RoleService;
import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdPayload;
import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import javax.validation.Valid;
-
/**
*
RoleRemoteApiController
*
* Change description here.
*
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
* @date 5/10/20 10:43 PM
**/
@RestController
@RequiredArgsConstructor
@RequestMapping("/role-remote-api")
-@Api(tags = {"Role Remote API Controller"})
+@Api(tags = {"Role Remote API"})
public class RoleRemoteApiController {
private final RoleService roleService;
- @PostMapping("/get-role-list-by-user-id")
- @ApiOperation(value = "/get-role-list-by-user-id", notes = "Get role list by user id")
- public ResponseBodyBean getRoleListByUserId(@Valid @RequestBody GetRoleListByUserIdPayload payload) {
- return ResponseBodyBean.ofSuccess(roleService.getRoleListByUserId(payload));
+ @GetMapping("/roles/{userId}")
+ @ApiOperation(value = "Get role list", notes = "Get role list (Remote API)")
+ public ResponseBodyBean getRoleList(@PathVariable Long userId) {
+ return ResponseBodyBean.ofSuccess(roleService.getRoleList(userId));
}
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/RolePersistence.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/RolePersistence.java
deleted file mode 100644
index 3a1cbcb0..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/RolePersistence.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.jmsoftware.maf.authcenter.role.entity;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * Role.(Role) Persistence object class
- *
- * @author Johnny Miller (鍾俊)
- * @since 2020-05-10 22:39:45
- */
-@Data
-public class RolePersistence implements Serializable {
- private static final long serialVersionUID = -81197803690669820L;
- /**
- * Primary key
- */
- private Long id;
- /**
- * Role name
- */
- private String name;
- /**
- * Role description
- */
- private String description;
- /**
- * Created time
- */
- private Date createdTime;
- /**
- * Modified time
- */
- private Date modifiedTime;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/constant/RoleRedisKey.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/constant/RoleRedisKey.java
new file mode 100644
index 00000000..da13f1c8
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/constant/RoleRedisKey.java
@@ -0,0 +1,22 @@
+package com.jmsoftware.maf.authcenter.role.entity.constant;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * RoleRedisKey
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com, 6/28/21 9:45 PM
+ **/
+@Getter
+@RequiredArgsConstructor
+public enum RoleRedisKey {
+ /**
+ * Get user by login token key pattern, expired in random [1, 7) days
+ */
+ GET_ROLE_LIST_BY_USER_ID(":role:get_role_list_by_user_id:%s");
+
+ private final String keyInfixFormat;
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/package-info.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/package-info.java
new file mode 100644
index 00000000..8db13650
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/package-info.java
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.role.entity;
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/persistence/Role.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/persistence/Role.java
new file mode 100644
index 00000000..c388c01b
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/entity/persistence/Role.java
@@ -0,0 +1,89 @@
+package com.jmsoftware.maf.authcenter.role.entity.persistence;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+import static com.baomidou.mybatisplus.annotation.FieldFill.INSERT;
+import static com.baomidou.mybatisplus.annotation.FieldFill.UPDATE;
+
+/**
+ *
Role
+ *
+ * Role Persistence object class
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 3:22 PM
+ */
+@Data
+@TableName(value = Role.TABLE_NAME)
+public class Role {
+ /**
+ * Primary key
+ */
+ @TableId(value = COL_ID, type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * Role name
+ */
+ @TableField(value = COL_NAME)
+ private String name;
+
+ /**
+ * Role description
+ */
+ @TableField(value = COL_DESCRIPTION)
+ private String description;
+
+ /**
+ * Created by
+ */
+ @TableField(value = COL_CREATED_BY, fill = INSERT)
+ private Long createdBy;
+
+ /**
+ * Created time
+ */
+ @TableField(value = COL_CREATED_TIME, fill = INSERT)
+ private Date createdTime;
+
+ /**
+ * Modified by
+ */
+ @TableField(value = COL_MODIFIED_BY, fill = UPDATE)
+ private Long modifiedBy;
+
+ /**
+ * Modified time
+ */
+ @TableField(value = COL_MODIFIED_TIME, fill = UPDATE)
+ private Date modifiedTime;
+
+ /**
+ * Deleted flag.
+ */
+ @TableField(value = COL_DELETED, fill = INSERT)
+ private Byte deleted;
+
+ public static final String TABLE_NAME = "role";
+
+ public static final String COL_ID = "id";
+
+ public static final String COL_NAME = "name";
+
+ public static final String COL_DESCRIPTION = "description";
+
+ public static final String COL_CREATED_BY = "created_by";
+
+ public static final String COL_CREATED_TIME = "created_time";
+
+ public static final String COL_MODIFIED_BY = "modified_by";
+
+ public static final String COL_MODIFIED_TIME = "modified_time";
+
+ public static final String COL_DELETED = "deleted";
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.java
index ce11eacd..77e86f1c 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.java
@@ -1,8 +1,9 @@
package com.jmsoftware.maf.authcenter.role.mapper;
-import com.jmsoftware.maf.authcenter.role.entity.RolePersistence;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jmsoftware.maf.authcenter.role.entity.persistence.Role;
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -11,65 +12,24 @@
*
* Mapper of Role.(Role)
*
- * @author Johnny Miller (鍾俊)
+ * @author Johnny Miller (锺俊)
* @date 2020 -05-10 22:39:48
*/
@Mapper
-public interface RoleMapper {
+public interface RoleMapper extends BaseMapper {
/**
- * Query by id role.
- *
- * @param id the id
- * @return the role
- */
- RolePersistence queryById(Long id);
-
- /**
- * Query all by limit list.
- *
- * @param offset the offset
- * @param limit the limit
- * @return the list
- */
- List queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);
-
- /**
- * Query all list.
+ * Select role list by user id list.
*
- * @param rolePersistence the role
+ * @param userId the user id
* @return the list
*/
- List queryAll(RolePersistence rolePersistence);
-
- /**
- * Insert int.
- *
- * @param rolePersistence the role
- * @return the int
- */
- int insert(RolePersistence rolePersistence);
+ List selectRoleListByUserId(Long userId);
/**
- * Update int.
+ * Select by id role persistence.
*
- * @param rolePersistence the role
- * @return the int
- */
- int update(RolePersistence rolePersistence);
-
- /**
- * Delete by id int.
- *
- * @param id the id
- * @return the int
- */
- int deleteById(Long id);
-
- /**
- * Select role list by user id list.
- *
- * @param userId the user id
- * @return the list
+ * @param roleName the role name
+ * @return the role persistence
*/
- List selectRoleListByUserId(Long userId);
+ Role selectByName(String roleName);
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleService.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleService.java
index e0f7500b..50e5f388 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleService.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleService.java
@@ -1,10 +1,14 @@
package com.jmsoftware.maf.authcenter.role.service;
-import com.jmsoftware.maf.authcenter.role.entity.RolePersistence;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdPayload;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jmsoftware.maf.authcenter.role.entity.persistence.Role;
import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse;
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
import lombok.NonNull;
+import org.springframework.validation.annotation.Validated;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
import java.util.List;
/**
@@ -12,25 +16,18 @@
*
* Service of Role.(Role)
*
- * @author Johnny Miller (鍾俊)
+ * @author Johnny Miller (锺俊)
* @date 2020 -05-10 22:39:49
*/
-public interface RoleService {
- /**
- * Query by ID
- *
- * @param id the primary key ID
- * @return the entity
- */
- RolePersistence queryById(Long id);
-
+@Validated
+public interface RoleService extends IService {
/**
* Gets role list by user id.
*
- * @param payload the payload
+ * @param userId the user id
* @return the role list by user id
*/
- GetRoleListByUserIdResponse getRoleListByUserId(GetRoleListByUserIdPayload payload);
+ GetRoleListByUserIdResponse getRoleList(@NotNull Long userId);
/**
* Gets role list by user id.
@@ -38,38 +35,13 @@ public interface RoleService {
* @param userId the user id
* @return the role list by user id
*/
- List getRoleListByUserId(@NonNull Long userId);
-
- /**
- * Query all by limit
- *
- * @param offset the offset
- * @param limit the limit
- * @return the entity list
- */
- List queryAllByLimit(int offset, int limit);
-
- /**
- * Insert
- *
- * @param rolePersistence the entity
- * @return the entity
- */
- RolePersistence insert(RolePersistence rolePersistence);
-
- /**
- * Update
- *
- * @param rolePersistence the entity
- * @return the entity
- */
- RolePersistence update(RolePersistence rolePersistence);
+ List getRoleListByUserId(@NonNull Long userId);
/**
- * Delete by ID
+ * Check admin boolean.
*
- * @param id the primary key ID
+ * @param roleIdList the role id list
* @return the boolean
*/
- boolean deleteById(Long id);
+ boolean checkAdmin(@NotEmpty List<@NotNull Long> roleIdList);
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleServiceImpl.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleServiceImpl.java
index 0e25e5df..fdc72e90 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleServiceImpl.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleServiceImpl.java
@@ -1,72 +1,83 @@
package com.jmsoftware.maf.authcenter.role.service.impl;
-import cn.hutool.core.bean.BeanUtil;
-import com.jmsoftware.maf.authcenter.role.entity.RolePersistence;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.jmsoftware.maf.authcenter.role.entity.constant.RoleRedisKey;
+import com.jmsoftware.maf.authcenter.role.entity.persistence.Role;
import com.jmsoftware.maf.authcenter.role.mapper.RoleMapper;
import com.jmsoftware.maf.authcenter.role.service.RoleService;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdPayload;
import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse;
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
+import com.jmsoftware.maf.springcloudstarter.configuration.MafConfiguration;
+import com.jmsoftware.maf.springcloudstarter.configuration.MafProjectProperty;
import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
import lombok.val;
+import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
-import javax.annotation.Resource;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
/**
* RoleServiceImpl
*
* Service implementation of Role.(Role)
*
- * @author Johnny Miller (鍾俊)
+ * @author Johnny Miller (锺俊)
* @date 2020-05-10 22:39:50
*/
-@Service("roleService")
-public class RoleServiceImpl implements RoleService {
- @Resource
- private RoleMapper roleMapper;
+@Service
+@RequiredArgsConstructor
+public class RoleServiceImpl extends ServiceImpl implements RoleService {
+ private final MafProjectProperty mafProjectProperty;
+ private final MafConfiguration mafConfiguration;
+ private final RedisTemplate redisTemplate;
+ private final ObjectMapper objectMapper;
@Override
- public RolePersistence queryById(Long id) {
- return this.roleMapper.queryById(id);
- }
-
- @Override
- public GetRoleListByUserIdResponse getRoleListByUserId(GetRoleListByUserIdPayload payload) {
- val roleList = this.getRoleListByUserId(payload.getUserId());
- GetRoleListByUserIdResponse response = new GetRoleListByUserIdResponse();
- roleList.forEach(rolePersistence -> {
- GetRoleListByUserIdResponse.Role role = new GetRoleListByUserIdResponse.Role();
- BeanUtil.copyProperties(rolePersistence, role);
- response.getRoleList().add(role);
- });
+ @SneakyThrows({JsonProcessingException.class})
+ public GetRoleListByUserIdResponse getRoleList(@NotNull Long userId) {
+ val key = String.format(mafProjectProperty.getProjectParentArtifactId()
+ + RoleRedisKey.GET_ROLE_LIST_BY_USER_ID.getKeyInfixFormat(), userId);
+ val hasKey = redisTemplate.hasKey(key);
+ if (BooleanUtil.isTrue(hasKey)) {
+ return objectMapper.readValue(redisTemplate.opsForValue().get(key), GetRoleListByUserIdResponse.class);
+ }
+ val response = new GetRoleListByUserIdResponse();
+ response.setRoleList(this.getRoleListByUserId(userId));
+ redisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(response), RandomUtil.randomLong(1, 7),
+ TimeUnit.DAYS);
return response;
}
@Override
- public List getRoleListByUserId(@NonNull Long userId) {
- return roleMapper.selectRoleListByUserId(userId);
- }
-
- @Override
- public List queryAllByLimit(int offset, int limit) {
- return this.roleMapper.queryAllByLimit(offset, limit);
- }
-
- @Override
- public RolePersistence insert(RolePersistence rolePersistence) {
- this.roleMapper.insert(rolePersistence);
- return rolePersistence;
- }
-
- @Override
- public RolePersistence update(RolePersistence rolePersistence) {
- this.roleMapper.update(rolePersistence);
- return this.queryById(rolePersistence.getId());
+ public List getRoleListByUserId(@NonNull Long userId) {
+ return this.getBaseMapper().selectRoleListByUserId(userId);
}
@Override
- public boolean deleteById(Long id) {
- return this.roleMapper.deleteById(id) > 0;
+ public boolean checkAdmin(@NotEmpty List<@NotNull Long> roleIdList) {
+ val wrapper = Wrappers.lambdaQuery(Role.class);
+ wrapper.select(Role::getName)
+ .in(Role::getId, roleIdList);
+ val roleList = this.list(wrapper);
+ val roleNameSet = roleList
+ .stream()
+ .map(Role::getName)
+ .filter(roleName -> StrUtil.equals(mafConfiguration.getSuperUserRole(), roleName))
+ .collect(Collectors.toSet());
+ // If roleNameSet is not empty (contains "admin")
+ return CollUtil.isNotEmpty(roleNameSet);
}
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/controller/JwtRemoteApiController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/controller/JwtRemoteApiController.java
new file mode 100644
index 00000000..f08559aa
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/controller/JwtRemoteApiController.java
@@ -0,0 +1,43 @@
+package com.jmsoftware.maf.authcenter.security.controller;
+
+import com.jmsoftware.maf.authcenter.security.service.JwtService;
+import com.jmsoftware.maf.common.bean.ResponseBodyBean;
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse;
+import com.jmsoftware.maf.common.exception.SecurityException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Description: JwtRemoteApiController, change description here.
+ *
+ * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/29/2020 11:04 AM
+ **/
+@Validated
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@Api(tags = {"JWT Remote API"})
+@RequestMapping("/jwt-remote-api")
+public class JwtRemoteApiController {
+ private final JwtService jwtService;
+
+ /**
+ * Parse response body bean.
+ *
+ * @return the response body bean
+ */
+ @GetMapping("/parse")
+ @ApiOperation(value = "Parse JWT", notes = "Parse JWT (Remote API)")
+ public ResponseBodyBean parse(HttpServletRequest request) throws SecurityException {
+ return ResponseBodyBean.ofSuccess(
+ new ParseJwtResponse().setUsername(jwtService.getUsernameFromRequest(request)));
+ }
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/JwtService.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.java
similarity index 79%
rename from auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/JwtService.java
rename to auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.java
index 0959d8c1..ddc5d5fe 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/JwtService.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.java
@@ -1,9 +1,10 @@
-package com.jmsoftware.maf.authcenter.universal.service;
+package com.jmsoftware.maf.authcenter.security.service;
import com.jmsoftware.maf.common.exception.SecurityException;
import io.jsonwebtoken.Claims;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
+import org.springframework.validation.annotation.Validated;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
@@ -14,9 +15,9 @@
*
* Change description here.
*
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/7/20 5:15 PM
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 10:44 AM
*/
+@Validated
public interface JwtService {
/**
* Create JWT string.
@@ -25,7 +26,7 @@ public interface JwtService {
* @param rememberMe the remember me
* @return the string
*/
- String createJwt(Authentication authentication, Boolean rememberMe) throws SecurityException;
+ String createJwt(Authentication authentication, Boolean rememberMe);
/**
* Create JWT string.
@@ -38,13 +39,14 @@ public interface JwtService {
* @return the JWT string
*/
String createJwt(Boolean rememberMe, Long id, String subject, List roles, Collection
- extends GrantedAuthority> authorities) throws SecurityException;
+ extends GrantedAuthority> authorities);
/**
* Parse JWT.
*
* @param jwt the jwt
* @return the claims
+ * @throws SecurityException the security exception
*/
Claims parseJwt(String jwt) throws SecurityException;
@@ -52,6 +54,7 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
* Invalidate jwt.
*
* @param request the request
+ * @throws SecurityException the security exception
*/
void invalidateJwt(HttpServletRequest request) throws SecurityException;
@@ -60,6 +63,7 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
*
* @param jwt the jwt
* @return the username from jwt
+ * @throws SecurityException the security exception
*/
String getUsernameFromJwt(String jwt) throws SecurityException;
@@ -68,6 +72,7 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
*
* @param request the request
* @return the username from request
+ * @throws SecurityException the security exception
*/
String getUsernameFromRequest(HttpServletRequest request) throws SecurityException;
diff --git a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/JwtServiceImpl.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.java
similarity index 67%
rename from api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/JwtServiceImpl.java
rename to auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.java
index 7ee57269..e72259de 100644
--- a/api-portal/src/main/java/com/jmsoftware/maf/apiportal/universal/service/impl/JwtServiceImpl.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.java
@@ -1,20 +1,20 @@
-package com.jmsoftware.maf.apiportal.universal.service.impl;
+package com.jmsoftware.maf.authcenter.security.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
-import com.jmsoftware.maf.apiportal.universal.configuration.Constants;
-import com.jmsoftware.maf.apiportal.universal.configuration.JwtConfiguration;
-import com.jmsoftware.maf.apiportal.universal.domain.UserPrincipal;
-import com.jmsoftware.maf.apiportal.universal.service.JwtService;
-import com.jmsoftware.maf.apiportal.universal.service.RedisService;
-import com.jmsoftware.maf.common.constant.HttpStatus;
+import com.jmsoftware.maf.authcenter.security.service.JwtService;
+import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
import com.jmsoftware.maf.common.exception.SecurityException;
+import com.jmsoftware.maf.springcloudstarter.configuration.JwtConfiguration;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
@@ -33,7 +33,7 @@
* JwtServiceImpl
* Change description here.
*
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
* @date 2019-03-03 13:40
**/
@Slf4j
@@ -42,7 +42,7 @@
@SuppressWarnings("unused")
public class JwtServiceImpl implements JwtService {
private final JwtConfiguration jwtConfiguration;
- private final RedisService redisService;
+ private final RedisTemplate redisTemplate;
private SecretKey secretKey;
private JwtParser jwtParser;
@@ -55,7 +55,7 @@ private void init() {
}
@Override
- public String createJwt(Authentication authentication, Boolean rememberMe) throws SecurityException {
+ public String createJwt(Authentication authentication, Boolean rememberMe) {
val userPrincipal = (UserPrincipal) authentication.getPrincipal();
return createJwt(rememberMe, userPrincipal.getId(), userPrincipal.getUsername(), userPrincipal.getRoles(),
userPrincipal.getAuthorities());
@@ -63,7 +63,7 @@ public String createJwt(Authentication authentication, Boolean rememberMe) throw
@Override
public String createJwt(Boolean rememberMe, Long id, String subject, List roles,
- Collection extends GrantedAuthority> authorities) throws SecurityException {
+ Collection extends GrantedAuthority> authorities) {
val now = new Date();
val builder = Jwts.builder()
.setId(id.toString())
@@ -71,7 +71,7 @@ public String createJwt(Boolean rememberMe, Long id, String subject, List new SecurityException(HttpStatus.TOKEN_PARSE_ERROR,
+ .orElseThrow(() -> new SecurityException(HttpStatus.INTERNAL_SERVER_ERROR,
"The JWT Claims Set is null", null));
} catch (ExpiredJwtException e) {
log.error("JWT is expired. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.TOKEN_EXPIRED);
+ throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (JWT itself)");
} catch (UnsupportedJwtException e) {
log.error("JWT is unsupported. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.TOKEN_PARSE_ERROR);
+ throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is unsupported");
} catch (MalformedJwtException e) {
log.error("JWT is invalid. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.TOKEN_PARSE_ERROR);
+ throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is invalid");
} catch (IllegalArgumentException e) {
log.error("The parameter of JWT is invalid. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.TOKEN_PARSE_ERROR);
+ throw new SecurityException(HttpStatus.UNAUTHORIZED, "The parameter of JWT is invalid");
}
val username = claims.getSubject();
- val redisKeyOfJwt = Constants.REDIS_JWT_KEY_PREFIX + username;
+ val redisKeyOfJwt = jwtConfiguration.getJwtRedisKeyPrefix() + username;
// Check if JWT exists
- val expire = redisService.getExpire(redisKeyOfJwt, TimeUnit.MILLISECONDS);
+ val expire = redisTemplate.opsForValue().getOperations().getExpire(redisKeyOfJwt, TimeUnit.MILLISECONDS);
if (ObjectUtil.isNull(expire) || expire <= 0) {
- throw new SecurityException(HttpStatus.TOKEN_EXPIRED);
+ throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (Redis expiration)");
}
// Check if the current JWT is equal to the one in Redis.
// If it's noe equal, that indicates current user has signed out or logged in before.
// Both situations reveal the JWT has expired.
- val jwtInRedis = redisService.get(redisKeyOfJwt);
+ val jwtInRedis = (String) redisTemplate.opsForValue().get(redisKeyOfJwt);
if (!StrUtil.equals(jwt, jwtInRedis)) {
- throw new SecurityException(HttpStatus.TOKEN_OUT_OF_CONTROL);
+ throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (Not equaled)");
}
return claims;
}
@@ -131,8 +128,9 @@ public void invalidateJwt(HttpServletRequest request) throws SecurityException {
val jwt = getJwtFromRequest(request);
val username = getUsernameFromJwt(jwt);
// Delete JWT from redis
- val deletedKeyNumber = redisService.delete(Constants.REDIS_JWT_KEY_PREFIX + username);
- log.error("Invalidate JWT. Username = {}, deleted = {}", username, deletedKeyNumber);
+ String redisKeyOfJwt = String.format("%s%s", jwtConfiguration.getJwtRedisKeyPrefix(), username);
+ val deletedKeyNumber = redisTemplate.opsForValue().getOperations().delete(redisKeyOfJwt);
+ log.error("Invalidate JWT. Redis key of JWT = {}, deleted = {}", redisKeyOfJwt, deletedKeyNumber);
}
@Override
@@ -149,9 +147,9 @@ public String getUsernameFromRequest(HttpServletRequest request) throws Security
@Override
public String getJwtFromRequest(HttpServletRequest request) {
- val bearerToken = request.getHeader(Constants.REQUEST_TOKEN_KEY);
- if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(Constants.JWT_PREFIX)) {
- return bearerToken.substring(Constants.JWT_PREFIX.length());
+ val bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION);
+ if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(JwtConfiguration.TOKEN_PREFIX)) {
+ return bearerToken.substring(JwtConfiguration.TOKEN_PREFIX.length());
}
return null;
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/Constants.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/Constants.java
deleted file mode 100644
index daf328d2..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/Constants.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-/**
- * Constants
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Slf4j
-@Component
-public class Constants {
- public Constants(ProjectProperty projectProperty) {
- REDIS_JWT_KEY_PREFIX = String.format("%s:jwt:", projectProperty.getProjectParentArtifactId());
- log.info("Initiated 'REDIS_JWT_KEY_PREFIX': {}", REDIS_JWT_KEY_PREFIX);
- }
-
- /**
- * Key prefix of JWT stored in Redis.
- */
- public static String REDIS_JWT_KEY_PREFIX;
- /**
- * Token key of request header.
- */
- public static final String REQUEST_TOKEN_KEY = "Authorization";
- /**
- * Prefix of JWT.
- */
- public static final String JWT_PREFIX = "Bearer ";
- /**
- * Star sign
- */
- public static final String ASTERISK = "*";
- /**
- * At sign
- */
- public static final String AT_SIGN = "@";
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/DruidConfiguration.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/DruidConfiguration.java
deleted file mode 100644
index f87bb65b..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/DruidConfiguration.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import com.alibaba.druid.pool.DruidDataSource;
-import com.alibaba.druid.support.http.StatViewServlet;
-import com.alibaba.druid.support.http.WebStatFilter;
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.boot.web.servlet.ServletRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import javax.sql.DataSource;
-
-/**
- *
DruidConfiguration
- *
- * Druid Configuration
- * Click me to view Druid Monitor
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-24 13:31
- **/
-@Configuration
-@RequiredArgsConstructor
-public class DruidConfiguration {
- @Bean
- public ServletRegistrationBean druidServlet() {
- val servletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
- servletRegistrationBean.addInitParameter("loginUsername", "admin");
- servletRegistrationBean.addInitParameter("loginPassword", "admin");
- servletRegistrationBean.addInitParameter("resetEnable", "false");
- return servletRegistrationBean;
- }
-
- @Bean
- public FilterRegistrationBean filterRegistrationBean() {
- val filterRegistrationBean = new FilterRegistrationBean();
- filterRegistrationBean.setFilter(new WebStatFilter());
- filterRegistrationBean.addUrlPatterns("/*");
- // Ignored resources
- filterRegistrationBean.addInitParameter("exclusions",
- "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
- filterRegistrationBean.addInitParameter("profileEnable", "true");
- filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
- filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
- return filterRegistrationBean;
- }
-
- @Bean
- @ConfigurationProperties(prefix = "spring.datasource")
- public DataSource druidDataSource() {
- return new DruidDataSource();
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/MyBatisPlusConfiguration.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/MyBatisPlusConfiguration.java
deleted file mode 100644
index 3097fc3f..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/MyBatisPlusConfiguration.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
-import lombok.val;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.transaction.annotation.EnableTransactionManagement;
-
-/**
- * MyBatisPlusConfiguration
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-05-02 11:57
- **/
-@Configuration
-@EnableTransactionManagement
-public class MyBatisPlusConfiguration {
- /**
- * Inject bean to enable pagination.
- *
- * @return bean for pagination
- */
- @Bean
- public PaginationInterceptor paginationInterceptor() {
- val paginationInterceptor = new PaginationInterceptor();
- // Set maximum query record count
- paginationInterceptor.setLimit(100L);
- // Enable JSQL Parser Count Optimizing (for left join)
- paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
- return paginationInterceptor;
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/ProjectProperty.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/ProjectProperty.java
deleted file mode 100644
index 527dc005..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/ProjectProperty.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
-
-/**
- *
ProjectProperty
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-04-18 13:01
- **/
-@Data
-@Component
-@ConfigurationProperties(prefix = "project.property")
-public class ProjectProperty {
- private String basePackage;
- private String contextPath;
- private String groupId;
- private String projectParentArtifactId;
- private String projectArtifactId;
- private String version;
- private String description;
- private String jdkVersion;
- private String environment;
- private String url;
- private String inceptionYear;
- private String organizationName;
- private String organizationUrl;
- private String issueManagementSystem;
- private String issueManagementUrl;
- private String developerName;
- private String developerEmail;
- private String developerUrl;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/RedisClientConfiguration.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/RedisClientConfiguration.java
deleted file mode 100644
index cc9b0956..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/RedisClientConfiguration.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import lombok.val;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
-import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
-import org.springframework.cache.annotation.CachingConfigurerSupport;
-import org.springframework.cache.annotation.EnableCaching;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
-import org.springframework.data.redis.serializer.StringRedisSerializer;
-
-import java.io.Serializable;
-
-/**
- *
RedisClientConfiguration
- *
- * Ignored request configuration.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Configuration
-@EnableCaching
-@AutoConfigureAfter(RedisAutoConfiguration.class)
-public class RedisClientConfiguration extends CachingConfigurerSupport {
- /**
- * Redis template. Support for <String, Serializable>
- */
- @Bean
- public RedisTemplate redisFactory(LettuceConnectionFactory lettuceConnectionFactory) {
- val template = new RedisTemplate();
- template.setKeySerializer(new StringRedisSerializer());
- template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
- template.setConnectionFactory(lettuceConnectionFactory);
- return template;
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/ServerConfiguration.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/ServerConfiguration.java
deleted file mode 100644
index a59eca85..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/ServerConfiguration.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.boot.web.context.WebServerInitializedEvent;
-import org.springframework.context.ApplicationListener;
-import org.springframework.stereotype.Component;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.URL;
-import java.util.Enumeration;
-
-/**
- * ServerConfiguration
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-04-26 16:02
- **/
-@Slf4j
-@Getter
-@Component
-@RequiredArgsConstructor
-public class ServerConfiguration implements ApplicationListener {
- private static final String DEVELOPMENT_ENVIRONMENT = "development";
- private final ProjectProperty projectProperty;
- private int serverPort;
-
- @Override
- public void onApplicationEvent(WebServerInitializedEvent event) {
- this.serverPort = event.getWebServer().getPort();
- }
-
- /**
- * Get base URL of backend server.
- * The result will be like:
- *
- * http://[serverIp]:[serverPort]/[contextPath]
- * https://[serverIp]/[contextPath]
- *
- *
- * @return base URL
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-05-03 16:05
- */
- public String getBaseUrl() {
- return "http://" + this.getPublicIp() + ":" + serverPort + projectProperty.getContextPath();
- }
-
- /**
- * Find public IP address.
- *
- * @return public IP
- */
- public String getPublicIp() {
- if (projectProperty.getEnvironment().contains(DEVELOPMENT_ENVIRONMENT)) {
- return this.getInternetIp();
- }
- try {
- // An API provided by https://whatismyipaddress.com/api
- val url = new URL("https://ipv4bot.whatismyipaddress.com/");
- val sc = new BufferedReader(new InputStreamReader(url.openStream()));
- // Read system IP Address
- return sc.readLine().trim();
- } catch (Exception e) {
- log.error("Cannot execute properly to get IP address from https://whatismyipaddress.com/api", e);
- }
- return this.getInternetIp();
- }
-
- /**
- * Get internet IP.
- *
- * @return internet IP
- */
- private String getInternetIp() {
- val intranetIp = this.getIntranetIp();
- try {
- val networks = NetworkInterface.getNetworkInterfaces();
- InetAddress ip;
- Enumeration addresses;
- while (networks.hasMoreElements()) {
- addresses = networks.nextElement().getInetAddresses();
- while (addresses.hasMoreElements()) {
- ip = addresses.nextElement();
- if (ip instanceof Inet4Address
- && ip.isSiteLocalAddress()
- && !ip.getHostAddress().equals(intranetIp)) {
- return ip.getHostAddress();
- }
- }
- }
- return intranetIp;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Get intranet IP.
- *
- * @return intranet IP
- */
- private String getIntranetIp() {
- try {
- return InetAddress.getLocalHost().getHostAddress();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpClientConfiguration.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpClientConfiguration.java
deleted file mode 100644
index fb7ce716..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpClientConfiguration.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import com.jcraft.jsch.ChannelSftp;
-import lombok.Data;
-import lombok.val;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.core.io.Resource;
-import org.springframework.expression.common.LiteralExpression;
-import org.springframework.integration.annotation.ServiceActivator;
-import org.springframework.integration.file.remote.session.CachingSessionFactory;
-import org.springframework.integration.file.remote.session.SessionFactory;
-import org.springframework.integration.sftp.outbound.SftpMessageHandler;
-import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
-import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
-import org.springframework.messaging.MessageHandler;
-import org.springframework.stereotype.Component;
-
-import java.io.File;
-
-/**
- * SftpClientConfiguration
- * SFTP client configuration
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-04 18:18
- **/
-@Data
-@Component
-@ConfigurationProperties(prefix = "sftp.client.configuration")
-public class SftpClientConfiguration {
- /**
- * SFTP server IP
- */
- private String host;
- /**
- * SFTP server port
- */
- private Integer port;
- /**
- * Login user
- */
- private String user;
- /**
- * Login password
- */
- private String password;
- /**
- * Remote directory
- */
- private String directory;
- /**
- * Private key
- */
- private Resource privateKey;
- /**
- * Private key pass phrase
- */
- private String privateKeyPassPhrase;
- /**
- * The maximum cache size of session. Default: 10
- */
- private Integer sessionCacheSize = 10;
- /**
- * The session wait timeout (time unit: MILLISECONDS). Default: 10 * 1000L (10 seconds)
- */
- private Long sessionWaitTimeout = 10 * 1000L;
-
- @Bean
- public SessionFactory sftpSessionFactory() {
- val factory = new DefaultSftpSessionFactory(true);
- factory.setHost(host);
- factory.setPort(port);
- factory.setUser(user);
- if (privateKey != null) {
- factory.setPrivateKey(privateKey);
- factory.setPrivateKeyPassphrase(privateKeyPassPhrase);
- } else {
- factory.setPassword(password);
- }
- factory.setAllowUnknownKeys(true);
- // We return a caching session factory, so that we don't have to reconnect to SFTP server for each time
- val cachingSessionFactory = new CachingSessionFactory<>(factory, sessionCacheSize);
- cachingSessionFactory.setSessionWaitTimeout(sessionWaitTimeout);
- return cachingSessionFactory;
- }
-
- @Bean
- @ServiceActivator(inputChannel = "toSftpChannel")
- @SuppressWarnings("UnresolvedMessageChannel")
- public MessageHandler handler(SessionFactory sftpSessionFactory) {
- val handler = new SftpMessageHandler(sftpSessionFactory);
- handler.setRemoteDirectoryExpression(new LiteralExpression(directory));
- handler.setFileNameGenerator(message -> {
- if (message.getPayload() instanceof File) {
- return ((File) message.getPayload()).getName();
- } else {
- throw new IllegalArgumentException("File expected as payload.");
- }
- });
- return handler;
- }
-
- @Bean
- public SftpRemoteFileTemplate template(SessionFactory sftpSessionFactory) {
- return new SftpRemoteFileTemplate(sftpSessionFactory);
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpSubDirectoryRunner.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpSubDirectoryRunner.java
deleted file mode 100644
index 85760bfe..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpSubDirectoryRunner.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import com.jmsoftware.maf.authcenter.universal.domain.SftpSubDirectory;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.integration.sftp.session.SftpRemoteFileTemplate;
-import org.springframework.stereotype.Component;
-
-/**
- * SftpSubDirectoryRunner
- * After dependency injection finished, we must inti the SFTP server's sub directory for out business. If you want
- * to customize initialization configuration, config SftpSubDirectory.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-05 08:51
- * @see SftpSubDirectory
- **/
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class SftpSubDirectoryRunner implements ApplicationRunner {
- private final SftpRemoteFileTemplate sftpRemoteFileTemplate;
- private final SftpClientConfiguration sftpClientConfiguration;
-
- @Override
- public void run(ApplicationArguments args) {
- sftpRemoteFileTemplate.setAutoCreateDirectory(true);
- sftpRemoteFileTemplate.execute(session -> {
- if (!session.exists(sftpClientConfiguration.getDirectory())) {
- log.info("Make directories for SFTP server. Directory: {}", sftpClientConfiguration.getDirectory());
- session.mkdir(sftpClientConfiguration.getDirectory());
- } else {
- log.info("SFTP server remote directory exists: {}", sftpClientConfiguration.getDirectory());
- }
- return null;
- });
-
- log.info("Staring to initial SFTP server sub directory.");
- sftpRemoteFileTemplate.execute(session -> {
- for (val sftpSubDirectory : SftpSubDirectory.values()) {
- val fullPath = sftpClientConfiguration.getDirectory() + sftpSubDirectory.getSubDirectory();
- if (!session.exists(fullPath)) {
- log.info("SFTP server sub directory does not exist. Creating sub directory: {}", fullPath);
- session.mkdir(fullPath);
- } else {
- log.info("SFTP server sub directory exists. Path: {}", fullPath);
- }
- }
- return null;
- });
- log.info("Initialing SFTP server sub directory is done.");
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpUploadGateway.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpUploadGateway.java
deleted file mode 100644
index dc144254..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/SftpUploadGateway.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import org.springframework.integration.annotation.Gateway;
-import org.springframework.integration.annotation.MessagingGateway;
-import org.springframework.stereotype.Component;
-
-import java.io.File;
-
-/**
- * SftpUploadGateway
- * Change description here
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-04 21:03
- **/
-@Component
-@MessagingGateway
-public interface SftpUploadGateway {
- /**
- * Upload file
- *
- * @param file file
- */
- @Gateway(requestChannel = "toSftpChannel")
- @SuppressWarnings("UnresolvedMessageChannel")
- void upload(File file);
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/Swagger2Configuration.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/Swagger2Configuration.java
deleted file mode 100644
index 9d18e778..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/Swagger2Configuration.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import springfox.documentation.builders.ApiInfoBuilder;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.service.ApiInfo;
-import springfox.documentation.service.Contact;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spring.web.plugins.Docket;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
-
-/**
- * Swagger2Configuration
- *
- * Swagger 2 Configuration
- * Click me to view
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-02-07 16:15
- **/
-@Configuration
-@EnableSwagger2
-@RequiredArgsConstructor
-public class Swagger2Configuration {
- private final ProjectProperty projectProperty;
- private static final String LINE_SEPARATOR = System.lineSeparator();
-
- @Bean
- public Docket createRestApi() {
- return new Docket(DocumentationType.SWAGGER_2)
- .apiInfo(apiInfo())
- .select()
- .apis(RequestHandlerSelectors.basePackage(projectProperty.getBasePackage()))
- .paths(PathSelectors.any())
- .build();
- }
-
- private ApiInfo apiInfo() {
- val projectArtifactId = projectProperty.getProjectArtifactId();
- val version = projectProperty.getVersion();
- val developerEmail = projectProperty.getDeveloperEmail();
- val developerUrl = projectProperty.getDeveloperUrl();
- return new ApiInfoBuilder()
- .title(String.format("API for %s@%s", projectArtifactId, version))
- .description(String.format("%s %sArtifact ID: %s%sEnvironment: %s",
- projectProperty.getDescription(),
- LINE_SEPARATOR,
- projectArtifactId,
- LINE_SEPARATOR,
- projectProperty.getEnvironment()))
- .contact(new Contact(String.format("%s, email: %s%sHome page: %s",
- projectProperty.getDeveloperName(),
- developerEmail,
- LINE_SEPARATOR,
- developerUrl),
- developerUrl, developerEmail))
- .version(version)
- .build();
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/WebSecurityConfiguration.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/WebSecurityConfiguration.java
deleted file mode 100644
index 8c32eadb..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/configuration/WebSecurityConfiguration.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.configuration;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-
-/**
- *
WebSecurityConfiguration
- *
- * Security handler configuration.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 5/2/20 11:41 PM
- **/
-@Slf4j
-@Configuration
-@EnableWebSecurity
-@RequiredArgsConstructor
-public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- // Disable web security.
- http.cors()
- // Disable CSRF (Cross-site request forgery)
- .and().csrf().disable()
- // Disable form login to use custom login
- .formLogin().disable()
- .httpBasic().disable()
- .authorizeRequests().anyRequest().permitAll();
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/controller/CommonController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/controller/CommonController.java
deleted file mode 100644
index a709eace..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/controller/CommonController.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.controller;
-
-import com.jmsoftware.maf.authcenter.universal.service.CommonService;
-import com.jmsoftware.maf.authcenter.universal.service.RedisService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.ValidationTestPayload;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.Map;
-
-/**
- *
CommonController
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2/4/20 10:29 AM
- **/
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/common")
-@Api(tags = {"Common Controller"})
-public class CommonController {
- private final CommonService commonService;
- private final RedisService redisService;
-
- @GetMapping("/app-info")
- @ApiOperation(value = "/app-info", notes = "Retrieve application information")
- public ResponseBodyBean> applicationInformation() {
- val data = commonService.getApplicationInfo();
- redisService.set("appInfo", data.toString());
- return ResponseBodyBean.ofSuccess(data, "Succeed to retrieve app info.");
- }
-
- @PostMapping("/validation-test")
- @ApiOperation(value = "/validation-test", notes = "Validation of request payload test")
- public ResponseBodyBean validationTest(@RequestBody ValidationTestPayload payload) {
- commonService.validateObject(payload);
- return ResponseBodyBean.ofSuccess(payload.getName(), "validationTest()");
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/controller/ErrorController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/controller/ErrorController.java
deleted file mode 100644
index 603c17ae..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/controller/ErrorController.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.controller;
-
-import io.swagger.annotations.Api;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.boot.autoconfigure.web.ServerProperties;
-import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
-import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
-import org.springframework.boot.web.servlet.error.ErrorAttributes;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-/**
- * ErrorController
- *
- * Error controller.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-02 16:56
- **/
-@Slf4j
-@RestController
-@Api(tags = {"Error Controller"})
-public class ErrorController extends BasicErrorController {
- public ErrorController(ErrorAttributes errorAttributes,
- ServerProperties serverProperties,
- List errorViewResolvers) {
- super(errorAttributes, serverProperties.getError(), errorViewResolvers);
- }
-
- @Override
- public ResponseEntity> error(HttpServletRequest request) {
- val httpStatus = getStatus(request);
- val body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
- body.put("message", httpStatus.getReasonPhrase());
- val optionalTrace = Optional.ofNullable(body.get("trace"));
- optionalTrace.ifPresent(trace -> {
- val message = body.get("message");
- val firstLineOfTrace = trace.toString().split("\\n")[0];
- val joinedMessage = String.format("%s %s", message, firstLineOfTrace);
- body.put("message", joinedMessage);
- body.put("trace", "Trace has been simplified. Refer to 'message'");
- });
- log.error("Captured HTTP request error. Response body = {}", body);
- return new ResponseEntity<>(body, httpStatus);
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/ApiStatus.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/ApiStatus.java
deleted file mode 100644
index 020997c0..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/ApiStatus.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import lombok.Getter;
-
-/**
- * Description: ApiStatus, change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-04-07 23:32
- **/
-@Getter
-public enum ApiStatus {
- /**
- * Idled API (not stored in db).
- */
- IDLED(0),
- /**
- * API in used (stored in db).
- */
- IN_USE(1);
-
- private final Integer status;
-
- ApiStatus(Integer status) {
- this.status = status;
- }
-
- /**
- * Get ApiStatus by status.
- *
- * @param status status code
- * @return ApiStatus enum
- */
- public static ApiStatus getByStatus(Integer status) {
- ApiStatus[] apiStatuses = ApiStatus.values();
- for (ApiStatus apiStatus : apiStatuses) {
- if (apiStatus.status.equals(status)) {
- return apiStatus;
- }
- }
- return null;
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/GetApiListPLO.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/GetApiListPLO.java
deleted file mode 100644
index d745c1ee..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/GetApiListPLO.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import com.jmsoftware.maf.common.bean.PaginationBase;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * GetApiListPLO
- * Change description here
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-05-11 13:48
- **/
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class GetApiListPLO extends PaginationBase {
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/GetUserInfoRO.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/GetUserInfoRO.java
deleted file mode 100644
index 48c49d31..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/GetUserInfoRO.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import lombok.Data;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * GetUserInfoRO
- * Change description here
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-06-30 11:01
- **/
-@Data
-public class GetUserInfoRO {
- private Long id;
- private String username;
- private String email;
- private String cellphone;
- private String fullName;
- private Date birthday;
- private String gender;
- private Integer status;
- private List usersRoles = new ArrayList<>();
-
- @Data
- public static class UsersRole {
- private Long roleId;
- private String roleName;
- private String roleDescription;
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/PermissionPO.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/PermissionPO.java
deleted file mode 100644
index 050ecb2d..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/PermissionPO.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * PermissionPO
- * Persistence class for table `t_permission`
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-23 19:48
- **/
-@Data
-public class PermissionPO {
- /**
- * Primary key
- */
- private Long id;
- /**
- * URL. If type of record is page (1), URL stands for route; if type of record is button (2), URL stands for API
- */
- private String url;
- /**
- * PermissionPO description
- */
- private String description;
- /**
- * PermissionPO type. Page-1, Button-2
- */
- private Integer type;
- /**
- * PermissionPO expression.
- */
- private String permissionExpression;
- /**
- * HTTP method of API.
- */
- private String method;
- /**
- * Sort.
- */
- private Integer sort;
- /**
- * Primary key of parent.
- */
- private Long parentId;
- /**
- * Deleted flag
- */
- private Byte deleted;
- /**
- * Created time
- */
- private Date createdTime;
- /**
- * Modified time
- */
- private Date modifiedTime;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/PermissionType.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/PermissionType.java
deleted file mode 100644
index 5f1c3955..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/PermissionType.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * PermissionType
- * Change description here
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-05-25 10:24
- **/
-@Slf4j
-@Getter
-public enum PermissionType {
- /**
- * Controller
- */
- CONTROLLER(0, "Controller"),
- /**
- * Page
- */
- PAGE(1, "Page"),
- /**
- * Button
- */
- BUTTON(2, "Button (API)");
-
- private final Integer type;
- private final String description;
-
- PermissionType(Integer type, String description) {
- this.type = type;
- this.description = description;
- }
-
- public static PermissionType getByType(Integer type) {
- PermissionType permissionType = null;
- PermissionType[] values = PermissionType.values();
- for (PermissionType pt : values) {
- if (pt.getType().equals(type)) {
- permissionType = pt;
- }
- }
- return permissionType;
- }
-
- /**
- * Get enum by name
- *
- * @param name enum name
- * @return enum
- */
- public static PermissionType getByName(String name) {
- try {
- return PermissionType.valueOf(name);
- } catch (IllegalArgumentException e) {
- log.error("Invalid enum name: {}", name, e);
- return null;
- }
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/RolePO.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/RolePO.java
deleted file mode 100644
index 74e2960a..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/RolePO.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * RolePO
- * Persistence class for table `t_role`
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-23 19:50
- **/
-@Data
-public class RolePO {
- /**
- * Primary key
- */
- private Long id;
- /**
- * Role name
- */
- private String name;
- /**
- * Role description
- */
- private String description;
- /**
- * Create time
- */
- private Date createdTime;
- /**
- * Modify time
- */
- private Date modifiedTime;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/RolePermissionPO.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/RolePermissionPO.java
deleted file mode 100644
index 7e7c8868..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/RolePermissionPO.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import lombok.Data;
-
-/**
- * RolePermissionPO
- * Role-permission relation. Persistence class for table `t_role_permission`
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-23 19:50
- **/
-@Data
-public class RolePermissionPO {
- /**
- * Role's ID.
- */
- private Long roleId;
- /**
- * Permission's ID.
- */
- private Long permissionId;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/SftpUploadFile.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/SftpUploadFile.java
deleted file mode 100644
index d352939e..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/SftpUploadFile.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import lombok.Builder;
-import lombok.Data;
-import org.springframework.integration.file.support.FileExistsMode;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import java.io.File;
-
-/**
- * SftpUploadFile
- * Change description here
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-06 11:22
- **/
-@Data
-@Builder
-public class SftpUploadFile {
- /**
- * File to be uploaded to SFTP server
- */
- @NotNull
- private File fileToBeUploaded;
- /**
- * SFTP server's sub directory (if sub directory does'nt exist, will be auto created). Not empty and it looks
- * like this: "/some/sub/directory/"
- */
- @NotEmpty
- private String subDirectory;
- /**
- * This enumeration indicates what action shall be taken in case the destination file already exists. In default,
- * it should be set as: FileExistsMode.REPLACE
- */
- @NotNull
- private FileExistsMode fileExistsMode;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/UserPO.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/UserPO.java
deleted file mode 100644
index 81adf4d0..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/UserPO.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * UserPO
- * Persistence class for table `t_user`
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-23 19:51
- **/
-@Data
-public class UserPO {
- /**
- * Primary key
- */
- private Long id;
- /**
- * Username
- */
- private String username;
- /**
- * Email
- */
- private String email;
- /**
- * Cellphone number
- */
- private String cellphone;
- /**
- * Password
- */
- private String password;
- /**
- * Nickname
- */
- private String fullName;
- /**
- * Birthday (yyyy-MM-dd)
- */
- private Date birthday;
- /**
- * 58 gender options
- */
- private String gender;
- /**
- * UserPersistence avatar full path on SFTP server
- */
- private String avatar;
- /**
- * Status. 1 - enabled, 2 - disabled
- */
- private Integer status;
- /**
- * Create time
- */
- private Date createdTime;
- /**
- * Modify time
- */
- private Date modifiedTime;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/UserPrincipal.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/UserPrincipal.java
deleted file mode 100644
index 2be1a4be..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/domain/UserPrincipal.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.domain;
-
-import cn.hutool.core.util.StrUtil;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.jmsoftware.maf.common.domain.authcenter.user.UserStatus;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-/**
- * UserPrincipal
- * Custom user details.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-23 20:52
- **/
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-public class UserPrincipal implements UserDetails {
- private static final long serialVersionUID = -53353171692896501L;
-
- /**
- * Primary key
- */
- private Long id;
- /**
- * Username
- */
- private String username;
- /**
- * Email
- */
- private String email;
- /**
- * Phone
- */
- private String cellphone;
- /**
- * Password
- */
- @JsonIgnore
- private String password;
- /**
- * Nickname
- */
- private String fullName;
- /**
- * Birthday
- */
- private Date birthday;
- /**
- * Gender
- */
- private String gender;
- /**
- * Status
- */
- private Integer status;
- /**
- * Create time
- */
- private Date gmtCreated;
- /**
- * Modify time
- */
- private Date gmtModified;
- /**
- * Roles that user has
- */
- private List roles;
- /**
- * Authorities that user has
- */
- private Collection extends GrantedAuthority> authorities;
-
- /**
- * Create user principal
- *
- * @param user user po
- * @param roleList role po list
- * @param permissionList permission po list
- * @return user principal
- */
- public static UserPrincipal create(UserPO user, List roleList, List permissionList) {
- List roleNames = roleList.stream().map(RolePO::getName).collect(Collectors.toList());
-
- List authorities =
- permissionList.stream()
- .filter(permission -> StrUtil.isNotBlank(permission.getPermissionExpression()))
- .map(permission -> new SimpleGrantedAuthority(permission.getPermissionExpression()))
- .collect(Collectors.toList());
-
- return new UserPrincipal(user.getId(),
- user.getUsername(),
- user.getEmail(),
- user.getCellphone(),
- user.getPassword(),
- user.getFullName(),
- user.getBirthday(),
- user.getGender(),
- user.getStatus(),
- user.getCreatedTime(),
- user.getModifiedTime(),
- roleNames,
- authorities);
- }
-
- @Override
- public Collection extends GrantedAuthority> getAuthorities() {
- return authorities;
- }
-
- @Override
- public String getPassword() {
- return password;
- }
-
- @Override
- public String getUsername() {
- return username;
- }
-
- @Override
- public boolean isAccountNonExpired() {
- return true;
- }
-
- @Override
- public boolean isAccountNonLocked() {
- return true;
- }
-
- @Override
- public boolean isCredentialsNonExpired() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return Objects.equals(this.status, UserStatus.ENABLED.getStatus());
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/RolePermissionMapper.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/RolePermissionMapper.java
deleted file mode 100644
index e58f431f..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/RolePermissionMapper.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.mapper;
-
-import com.jmsoftware.maf.authcenter.universal.domain.RolePermissionPO;
-import org.apache.ibatis.annotations.Mapper;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-
-/**
- * RolePermissionMapper
- * CRUD operations for table `t_role_permission`
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-02 17:55
- **/
-@Mapper
-@Component
-public interface RolePermissionMapper {
- /**
- * Delete by role's ID
- *
- * @param po persistence object
- * @return affected row
- */
- Integer deleteByRoleId(RolePermissionPO po);
-
- /**
- * Insert a batch of records
- *
- * @param poList PO list
- * @return affected row
- */
- Integer insertBatch(List poList);
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/UserMapper.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/UserMapper.java
deleted file mode 100644
index c60a674f..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/UserMapper.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.jmsoftware.maf.authcenter.universal.domain.UserPO;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-import java.util.Optional;
-
-/**
- * UserMapper
- * CRUD operations for table `t_user`
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-02 17:32
- **/
-//@Mapper
-//@Component
-public interface UserMapper extends BaseMapper {
- /**
- * Find by username, email or cellphone.
- *
- * TODO: do not retrieve useless fields on result map
- *
- * @param username Username
- * @param email Email
- * @param cellphone cellphone number
- * @return User information.
- */
- Optional selectByUsernameOrEmailOrCellphone(@Param("username") String username,
- @Param("email") String email,
- @Param("cellphone") String cellphone);
-
- /**
- * Count by username.
- *
- * @param username username string
- * @return the count of username occurrence
- */
- Integer countByUsername(String username);
-
- /**
- * Count by email.
- *
- * @param email email string
- * @return the count of email occurrence
- */
- Integer countByEmail(String email);
-
- /**
- * Save user
- *
- * @param po A new user.
- * @return Last inserted ID.
- */
- Long save(UserPO po);
-
- /**
- * Register
- *
- * @param po UserPersistence info
- * @return Registered user ID
- */
- Long register(UserPO po);
-
- /**
- * Select user page list
- *
- * @param page pagination object
- * @return user page list
- */
- IPage selectUserPageList(Page page);
-
- /**
- * Select user by ID and status
- *
- * @param params query params
- * @return user persistence object
- */
- UserPO selectByIdAndStatus(@Param("params") UserPO params);
-
- /**
- * Update user's basic information by ID
- *
- * @param updated updated user
- * @return affected rows
- */
- int updateUserBasicInfoById(@Param("updated") UserPO updated);
-
- /**
- * Select user by username
- *
- * @param username username
- * @return user po
- */
- UserPO selectByUsername(@Param("username") String username);
-
- /**
- * Select user list for lazy selection
- *
- * @param page pagination object
- * @return user page list
- */
- IPage selectUserListForSelection(Page page);
-
- /**
- * Select user status by ID and username
- *
- * @param id user ID
- * @param username username
- * @return user status
- */
- Integer selectStatusByIdAndUsername(@Param("id") Long id, @Param("username") String username);
-
- /**
- * Insert user-role relation
- *
- * @param userId user ID
- * @param roleIdList role ID list
- * @return affected rows
- */
- int insertUserIdAndRoleIdList(@Param("userId") Long userId, @Param("roleIdList") List roleIdList);
-
- /**
- * Update avatar by user's ID
- *
- * @param po persistence object
- * @return affected rows
- */
- int updateAvatarByUsername(@Param("updated") UserPO po);
-
- /**
- * Select user's ID and avatar by username
- *
- * @param username username
- * @return po
- */
- UserPO selectIdAndAvatarByUsername(@Param("username") String username);
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/UserRoleMapper.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/UserRoleMapper.java
deleted file mode 100644
index fd63ca88..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/mapper/UserRoleMapper.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.mapper;
-
-/**
- * UserRoleMapper
- * CRUD operations for table `t_user_role`
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-02 17:33
- **/
-public interface UserRoleMapper {
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/RedisService.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/RedisService.java
deleted file mode 100644
index c5c4b331..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/RedisService.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.service;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * RedisService
- * Redis service interface for Redis useful operations
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-05 09:38
- **/
-public interface RedisService {
- /**
- * Set key and value in Redis with expiration
- *
- * @param key key
- * @param value value
- * @param expirationTime expiration time
- * @param timeUnit time unit
- * @return true - operation done; false - operation failure
- */
- Boolean set(String key, String value, Long expirationTime, TimeUnit timeUnit);
-
- /**
- * Set key and list in Redis with expiration
- *
- * @param key key
- * @param list list
- * @param expirationTime expiration time
- * @param timeUnit time unit
- * @return true - operation done; false - operation failure
- */
- Boolean set(String key, List list, Long expirationTime, TimeUnit timeUnit);
-
- /**
- * Set key and value in Redis
- *
- * @param key key
- * @param value value
- * @return true - operation done; false - operation failure
- */
- Boolean set(String key, String value);
-
- /**
- * Set key and list in Redis
- *
- * @param key key
- * @param list list
- * @return true - operation done; false - operation failure
- */
- Boolean set(String key, List list);
-
- /**
- * Make key expire
- *
- * @param key key
- * @param expirationTime expiration time
- * @param timeUnit time unit
- * @return true - operation done; false - operation failure
- */
- Boolean expire(String key, long expirationTime, TimeUnit timeUnit);
-
- /**
- * Get expiration time by key
- *
- * @param key key
- * @param timeUnit time unit
- * @return expiration time. Null when used in pipeline / transaction.
- */
- Long getExpire(String key, TimeUnit timeUnit);
-
- /**
- * Get value by key
- *
- * @param key key
- * @return null when key does not exist or used in pipeline / transaction.
- */
- String get(String key);
-
- /**
- * Get list by key
- *
- * @param key key
- * @param clazz type
- * @return null when key does not exist or used in pipeline / transaction.
- */
- List get(String key, Class clazz);
-
- /**
- * Delete by key
- *
- * @param key key
- * @return the number of keys that were removed. Null when used in pipeline / transaction.
- */
- Long delete(String key);
-
- /**
- * Delete by keys
- *
- * @param keys key list
- * @return the number of keys that were removed. Null when used in pipeline / transaction.
- */
- Long delete(Collection keys);
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/CommonServiceImpl.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/CommonServiceImpl.java
deleted file mode 100644
index 944aab7c..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/CommonServiceImpl.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.service.impl;
-
-import com.jmsoftware.maf.authcenter.universal.configuration.ProjectProperty;
-import com.jmsoftware.maf.authcenter.universal.service.CommonService;
-import com.jmsoftware.maf.common.domain.ValidationTestPayload;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import javax.validation.Valid;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * CommonServiceImpl
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2/4/20 11:16 AM
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class CommonServiceImpl implements CommonService {
- private final ProjectProperty projectProperty;
-
- @Override
- public Map getApplicationInfo() {
- var map = new HashMap(16);
- var fieldsInfo = getFieldsInfo(projectProperty);
- fieldsInfo.forEach(fieldInfo -> {
- var type = fieldInfo.get("type");
- if ("class java.lang.String".equals(type)) {
- map.put((String) fieldInfo.get("name"), fieldInfo.get("value"));
- }
- });
- return map;
- }
-
- @Override
- public void validateObject(@Valid ValidationTestPayload payload) {
- log.info("Validation passed! {}", payload);
- }
-
- /**
- * Gets field value by name.
- *
- * @param fieldName the field name
- * @param object the object
- * @return the field value by name
- * @see Java 中遍历一个对象的所有属性
- */
- private Object getFieldValueByName(String fieldName, Object object) {
- try {
- String firstLetter = fieldName.substring(0, 1).toUpperCase();
- String getter = "get" + firstLetter + fieldName.substring(1);
- Method method = object.getClass().getMethod(getter);
- return method.invoke(object);
- } catch (Exception e) {
- log.error("Can't get field's value by name! Cause: {}", e.getMessage());
- return null;
- }
- }
-
- /**
- * Get filed name string [ ].
- *
- * @param o the o
- * @return the string [ ]
- * @see Java 中遍历一个对象的所有属性
- */
- private String[] getFiledName(Object o) {
- Field[] fields = o.getClass().getDeclaredFields();
- String[] fieldNames = new String[fields.length];
- for (int i = 0; i < fields.length; i++) {
- log.info("fields[i].getType(): {}", fields[i].getType());
- fieldNames[i] = fields[i].getName();
- }
- return fieldNames;
- }
-
- /**
- * Get Fields Info
- *
- * @param o the o
- * @return the fields info
- * @see Java 中遍历一个对象的所有属性
- */
- private List> getFieldsInfo(Object o) {
- Field[] fields = o.getClass().getDeclaredFields();
- var arrayList = new ArrayList>();
- for (Field field : fields) {
- var infoMap = new HashMap(16);
- infoMap.put("type", field.getType().toString());
- infoMap.put("name", field.getName());
- infoMap.put("value", getFieldValueByName(field.getName(), o));
- arrayList.add(infoMap);
- }
- return arrayList;
- }
-
- /**
- * Get Filed Values
- *
- * @param o the o
- * @return the object [ ]
- * @see Java 中遍历一个对象的所有属性
- */
- public Object[] getFiledValues(Object o) {
- String[] fieldNames = this.getFiledName(o);
- Object[] value = new Object[fieldNames.length];
- for (int i = 0; i < fieldNames.length; i++) {
- value[i] = this.getFieldValueByName(fieldNames[i], o);
- }
- return value;
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/JwtServiceImpl.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/JwtServiceImpl.java
deleted file mode 100644
index 7eba09d7..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/JwtServiceImpl.java
+++ /dev/null
@@ -1,158 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.service.impl;
-
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.jmsoftware.maf.authcenter.universal.configuration.Constants;
-import com.jmsoftware.maf.authcenter.universal.configuration.JwtConfiguration;
-import com.jmsoftware.maf.authcenter.universal.domain.UserPrincipal;
-import com.jmsoftware.maf.authcenter.universal.service.JwtService;
-import com.jmsoftware.maf.authcenter.universal.service.RedisService;
-import com.jmsoftware.maf.common.constant.HttpStatus;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import io.jsonwebtoken.*;
-import io.jsonwebtoken.security.Keys;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.PostConstruct;
-import javax.crypto.SecretKey;
-import javax.servlet.http.HttpServletRequest;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-
-/**
- * JwtServiceImpl
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-03-03 13:40
- **/
-@Slf4j
-@Service
-@RequiredArgsConstructor
-@SuppressWarnings("unused")
-public class JwtServiceImpl implements JwtService {
- private final JwtConfiguration jwtConfiguration;
- private final RedisService redisService;
- private SecretKey secretKey;
- private JwtParser jwtParser;
-
- @PostConstruct
- private void init() {
- log.info("Start to init class members of {}.", this.getClass().getSimpleName());
- secretKey = Keys.hmacShaKeyFor(jwtConfiguration.getSigningKey().getBytes(StandardCharsets.UTF_8));
- log.warn("Secret key for JWT was generated. Algorithm: {}", secretKey.getAlgorithm());
- jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();
- }
-
- @Override
- public String createJwt(Authentication authentication, Boolean rememberMe) throws SecurityException {
- val userPrincipal = (UserPrincipal) authentication.getPrincipal();
- return createJwt(rememberMe, userPrincipal.getId(), userPrincipal.getUsername(), userPrincipal.getRoles(),
- userPrincipal.getAuthorities());
- }
-
- @Override
- public String createJwt(Boolean rememberMe, Long id, String subject, List roles,
- Collection extends GrantedAuthority> authorities) throws SecurityException {
- val now = new Date();
- val builder = Jwts.builder()
- .setId(id.toString())
- .setSubject(subject)
- .setIssuedAt(now)
- .signWith(secretKey)
- .claim("roles", roles);
- // TODO: Don't generate authority information in JWT.
- // .claim("authorities", authorities)
- // Set expire duration of JWT.
- val ttl = rememberMe ? jwtConfiguration.getTtlForRememberMe() : jwtConfiguration.getTtl();
- if (ttl > 0) {
- builder.setExpiration(DateUtil.offsetMillisecond(now, ttl.intValue()));
- }
- val jwt = builder.compact();
- // Store new JWT in Redis
- val redisOperationResult = redisService.set(Constants.REDIS_JWT_KEY_PREFIX + subject, jwt, ttl,
- TimeUnit.MILLISECONDS);
- if (redisOperationResult) {
- return jwt;
- } else {
- throw new SecurityException(HttpStatus.ERROR, "Cannot persist JWT into Redis", null);
- }
- }
-
- @Override
- public Claims parseJwt(String jwt) throws SecurityException {
- Claims claims;
- try {
- claims = Optional.ofNullable(jwtParser.parseClaimsJws(jwt).getBody())
- .orElseThrow(() -> new SecurityException(HttpStatus.TOKEN_PARSE_ERROR,
- "The JWT Claims Set is null", null));
- } catch (ExpiredJwtException e) {
- log.error("JWT is expired. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.TOKEN_EXPIRED);
- } catch (UnsupportedJwtException e) {
- log.error("JWT is unsupported. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.TOKEN_PARSE_ERROR);
- } catch (MalformedJwtException e) {
- log.error("JWT is invalid. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.TOKEN_PARSE_ERROR);
- } catch (IllegalArgumentException e) {
- log.error("The parameter of JWT is invalid. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.TOKEN_PARSE_ERROR);
- }
- val username = claims.getSubject();
- val redisKeyOfJwt = Constants.REDIS_JWT_KEY_PREFIX + username;
- // Check if JWT exists
- val expire = redisService.getExpire(redisKeyOfJwt, TimeUnit.MILLISECONDS);
- if (ObjectUtil.isNull(expire) || expire <= 0) {
- throw new SecurityException(HttpStatus.TOKEN_EXPIRED);
- }
- // Check if the current JWT is equal to the one in Redis.
- // If it's noe equal, that indicates current user has signed out or logged in before.
- // Both situations reveal the JWT has expired.
- val jwtInRedis = redisService.get(redisKeyOfJwt);
- if (!StrUtil.equals(jwt, jwtInRedis)) {
- throw new SecurityException(HttpStatus.TOKEN_OUT_OF_CONTROL);
- }
- return claims;
- }
-
- @Override
- public void invalidateJwt(HttpServletRequest request) throws SecurityException {
- val jwt = getJwtFromRequest(request);
- val username = getUsernameFromJwt(jwt);
- // Delete JWT from redis
- val deletedKeyNumber = redisService.delete(Constants.REDIS_JWT_KEY_PREFIX + username);
- log.error("Invalidate JWT. Username = {}, deleted = {}", username, deletedKeyNumber);
- }
-
- @Override
- public String getUsernameFromJwt(String jwt) throws SecurityException {
- val claims = parseJwt(jwt);
- return claims.getSubject();
- }
-
- @Override
- public String getUsernameFromRequest(HttpServletRequest request) throws SecurityException {
- val jwt = this.getJwtFromRequest(request);
- return this.getUsernameFromJwt(jwt);
- }
-
- @Override
- public String getJwtFromRequest(HttpServletRequest request) {
- val bearerToken = request.getHeader(Constants.REQUEST_TOKEN_KEY);
- if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(Constants.JWT_PREFIX)) {
- return bearerToken.substring(Constants.JWT_PREFIX.length());
- }
- return null;
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/RedisServiceImpl.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/RedisServiceImpl.java
deleted file mode 100644
index 39c3fc03..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/universal/service/impl/RedisServiceImpl.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.jmsoftware.maf.authcenter.universal.service.impl;
-
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONUtil;
-import com.jmsoftware.maf.authcenter.universal.service.RedisService;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.data.redis.connection.RedisStringCommands;
-import org.springframework.data.redis.core.RedisCallback;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.types.Expiration;
-import org.springframework.stereotype.Service;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-
-/**
- * RedisServiceImpl
- * Redis service implementation for Redis useful operations
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 2019-07-05 09:39
- **/
-@Service
-public class RedisServiceImpl implements RedisService {
- private final RedisTemplate redisTemplate;
-
- public RedisServiceImpl(@Qualifier("redisFactory") RedisTemplate redisTemplate) {
- this.redisTemplate = redisTemplate;
- }
-
- @Override
- public Boolean set(String key, String value, Long expirationTime, TimeUnit timeUnit) {
- return redisTemplate.execute((RedisCallback) connection -> {
- var serializer = redisTemplate.getStringSerializer();
- var result = connection.set(Objects.requireNonNull(serializer.serialize(key)),
- Objects.requireNonNull(serializer.serialize(value)),
- Expiration.from(expirationTime, timeUnit),
- RedisStringCommands.SetOption.upsert());
- return ObjectUtil.isNotNull(result) ? result : false;
- });
- }
-
- @Override
- public Boolean set(String key, List list, Long expirationTime, TimeUnit timeUnit) {
- var value = JSONUtil.toJsonStr(list);
- return set(key, value, expirationTime, timeUnit);
- }
-
- @Override
- public Boolean set(String key, String value) {
- return redisTemplate.execute((RedisCallback) connection -> {
- var serializer = redisTemplate.getStringSerializer();
- var result = connection.set(Objects.requireNonNull(serializer.serialize(key)),
- Objects.requireNonNull(serializer.serialize(value)));
- return ObjectUtil.isNotNull(result) ? result : false;
- });
- }
-
- @Override
- public Boolean set(String key, List list) {
- var value = JSONUtil.toJsonStr(list);
- return set(key, value);
- }
-
- @Override
- public Boolean expire(String key, long expirationTime, TimeUnit timeUnit) {
- var result = redisTemplate.expire(key, expirationTime, timeUnit);
- return ObjectUtil.isNotNull(result) ? result : false;
- }
-
- @Override
- public Long getExpire(String key, TimeUnit timeUnit) {
- return redisTemplate.getExpire(key, timeUnit);
- }
-
- @Override
- public String get(String key) {
- return redisTemplate.execute((RedisCallback) connection -> {
- var serializer = redisTemplate.getStringSerializer();
- var bytes = connection.get(Objects.requireNonNull(serializer.serialize(key)));
- return serializer.deserialize(bytes);
- });
- }
-
- @Override
- public List get(String key, Class clazz) {
- var json = get(key);
- if (StrUtil.isNotBlank(json)) {
- return JSONUtil.toList(JSONUtil.parseArray(json), clazz);
- }
- return null;
- }
-
- @Override
- public Long delete(String key) {
- return redisTemplate.execute((RedisCallback) connection -> {
- var serializer = redisTemplate.getStringSerializer();
- return connection.del(serializer.serialize(key));
- });
- }
-
- @Override
- public Long delete(Collection keys) {
- return redisTemplate.delete(keys);
- }
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/controller/UserController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/controller/UserController.java
index 778567a9..36b0a901 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/controller/UserController.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/controller/UserController.java
@@ -1,21 +1,60 @@
package com.jmsoftware.maf.authcenter.user.controller;
+import com.jmsoftware.maf.authcenter.user.entity.GetUserStatusPayload;
import com.jmsoftware.maf.authcenter.user.service.UserService;
+import com.jmsoftware.maf.common.bean.ResponseBodyBean;
+import com.jmsoftware.maf.common.domain.authcenter.user.LoginPayload;
+import com.jmsoftware.maf.common.domain.authcenter.user.LoginResponse;
+import com.jmsoftware.maf.common.domain.authcenter.user.SignupPayload;
+import com.jmsoftware.maf.common.domain.authcenter.user.SignupResponse;
+import com.jmsoftware.maf.common.exception.SecurityException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
- /**
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+
+/**
* UserController
*
* Controller implementation of UserPersistence.(UserPersistence)
*
- * @author Johnny Miller (鍾俊)
+ * @author Johnny Miller (锺俊)
* @date 2020-05-10 12:08:28
*/
+@Validated
@RestController
@RequiredArgsConstructor
-@RequestMapping("/user")
+@Api(tags = {"User API"})
public class UserController {
private final UserService userService;
+
+ @PostMapping("/users/signup")
+ @ApiOperation(value = "Signup", notes = "Save user for signup")
+ public ResponseBodyBean signup(@Valid @RequestBody SignupPayload payload) {
+ return ResponseBodyBean.ofSuccess(userService.saveUserForSignup(payload));
+ }
+
+ @PostMapping("/users/login")
+ @ApiOperation(value = "Login", notes = "Login")
+ public ResponseBodyBean login(@Valid @RequestBody LoginPayload payload) throws SecurityException {
+ return ResponseBodyBean.ofSuccess(userService.login(payload));
+ }
+
+ @PostMapping("/users/logout")
+ @ApiOperation(value = "Logout", notes = "Logout")
+ public ResponseBodyBean logout(HttpServletRequest request) throws SecurityException {
+ return ResponseBodyBean.ofSuccess(userService.logout(request));
+ }
+
+ @GetMapping("/users/status")
+ public ResponseBodyBean getUserStatus(@Valid GetUserStatusPayload payload) {
+ return ResponseBodyBean.ofSuccess(userService.getUserStatus(payload), "Correct enum value");
+ }
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/controller/UserRemoteApiController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/controller/UserRemoteApiController.java
new file mode 100644
index 00000000..dbd107fd
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/controller/UserRemoteApiController.java
@@ -0,0 +1,46 @@
+package com.jmsoftware.maf.authcenter.user.controller;
+
+import com.jmsoftware.maf.authcenter.user.entity.GetUserPageListPayload;
+import com.jmsoftware.maf.authcenter.user.entity.persistence.User;
+import com.jmsoftware.maf.authcenter.user.service.UserService;
+import com.jmsoftware.maf.common.bean.PageResponseBodyBean;
+import com.jmsoftware.maf.common.bean.ResponseBodyBean;
+import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+
+/**
+ * UserRemoteApiController
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
+ * @date 5/10/20 12:36 PM
+ **/
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/user-remote-api")
+@Api(tags = {"User Remote API"})
+public class UserRemoteApiController {
+ private final UserService userService;
+
+ @GetMapping("/users/{loginToken}")
+ @ApiOperation(value = "Get user by login token", notes = "Get user by login token (Remote)")
+ public ResponseBodyBean getUserByLoginToken(@PathVariable String loginToken) {
+ return ResponseBodyBean.ofSuccess(userService.getUserByLoginToken(loginToken));
+ }
+
+ @GetMapping("/users")
+ public PageResponseBodyBean getUserPageList(@Valid GetUserPageListPayload payload) {
+ return userService.getUserPageList(payload);
+ }
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/GetUserPageListPayload.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/GetUserPageListPayload.java
new file mode 100644
index 00000000..c0b293c1
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/GetUserPageListPayload.java
@@ -0,0 +1,28 @@
+package com.jmsoftware.maf.authcenter.user.entity;
+
+import com.jmsoftware.maf.common.bean.PaginationBase;
+import com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeConstraints;
+import com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeGroup;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+import static com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeType.END_TIME;
+import static com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeType.START_TIME;
+
+/**
+ * Description: GetUserPageList, change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 4:32 PM
+ **/
+@Data
+@DateTimeRangeConstraints
+@EqualsAndHashCode(callSuper = true)
+public class GetUserPageListPayload extends PaginationBase {
+ private String username;
+ @DateTimeRangeGroup(type = START_TIME)
+ private LocalDateTime startTime;
+ @DateTimeRangeGroup(type = END_TIME)
+ private LocalDateTime endTime;
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/GetUserStatusPayload.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/GetUserStatusPayload.java
new file mode 100644
index 00000000..af7a007a
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/GetUserStatusPayload.java
@@ -0,0 +1,22 @@
+package com.jmsoftware.maf.authcenter.user.entity;
+
+import com.jmsoftware.maf.common.domain.authcenter.user.UserStatus;
+import com.jmsoftware.maf.common.domain.authcenter.user.UserStatus2;
+import com.jmsoftware.maf.springcloudstarter.validation.annotation.ValidEnumValue;
+import lombok.Data;
+
+/**
+ * GetUserStatusPayload
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
+ * @date 6/6/21 4:31 PM
+ **/
+@Data
+public class GetUserStatusPayload {
+ @ValidEnumValue(targetEnum = UserStatus.class)
+ private Byte status;
+ @ValidEnumValue(targetEnum = UserStatus2.class)
+ private Byte status2;
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/UserPersistence.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/UserPersistence.java
deleted file mode 100644
index bdb46ee6..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/UserPersistence.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.entity;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- *
UserPersistence
- *
- * User Persistence object class
- *
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
- * @date 5/10/20 12:12 PM
- */
-@Data
-public class UserPersistence implements Serializable {
- private static final long serialVersionUID = -11418821727467072L;
- /**
- * Primary key of user
- */
- private Long id;
- /**
- * Username
- */
- private String username;
- /**
- * Email
- */
- private String email;
- /**
- * Cellphone number
- */
- private String cellphone;
- /**
- * Password
- */
- private String password;
- /**
- * Full name
- */
- private String fullName;
- /**
- * Birthday
- */
- private Date birthday;
- /**
- * 26 gender options
- */
- private String gender;
- /**
- * UserPersistence avatar full path on SFTP server
- */
- private String avatar;
- /**
- * Status. 1 - enabled, 2 - disabled
- */
- private Integer status;
- /**
- * Created time
- */
- private Date createdTime;
- /**
- * Modified time
- */
- private Date modifiedTime;
-}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/constant/UserRedisKey.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/constant/UserRedisKey.java
new file mode 100644
index 00000000..28cf2361
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/constant/UserRedisKey.java
@@ -0,0 +1,20 @@
+package com.jmsoftware.maf.authcenter.user.entity.constant;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Description: UserRedisKey, change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/28/2021 3:18 PM
+ **/
+@Getter
+@RequiredArgsConstructor
+public enum UserRedisKey {
+ /**
+ * Get user by login token key pattern, expired in random [1, 7) days
+ */
+ GET_USER_BY_LOGIN_TOKEN(":user:get_user_by_login_token:%s");
+
+ private final String keyInfixFormat;
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/persistence/User.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/persistence/User.java
new file mode 100644
index 00000000..37bb3f7a
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/persistence/User.java
@@ -0,0 +1,143 @@
+package com.jmsoftware.maf.authcenter.user.entity.persistence;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.util.Date;
+
+import static com.baomidou.mybatisplus.annotation.FieldFill.INSERT;
+import static com.baomidou.mybatisplus.annotation.FieldFill.UPDATE;
+
+/**
+ *
User
+ *
+ * User Persistence object class
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 3:22 PM
+ */
+@Data
+@SuppressWarnings("jol")
+@TableName(value = User.TABLE_NAME)
+public class User {
+ /**
+ * Primary key of user
+ */
+ @TableId(value = COL_ID, type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * Username
+ */
+ @TableField(value = COL_USERNAME)
+ private String username;
+
+ /**
+ * Email
+ */
+ @TableField(value = COL_EMAIL)
+ private String email;
+
+ /**
+ * Cellphone number
+ */
+ @TableField(value = COL_CELLPHONE)
+ private String cellphone;
+
+ /**
+ * Password
+ */
+ @TableField(value = COL_PASSWORD)
+ private String password;
+
+ /**
+ * Full name
+ */
+ @TableField(value = COL_FULL_NAME)
+ private String fullName;
+
+ /**
+ * Birthday
+ */
+ @TableField(value = COL_BIRTHDAY)
+ private Date birthday;
+
+ /**
+ * 26 gender options
+ */
+ @TableField(value = COL_GENDER)
+ private Object gender;
+
+ /**
+ * User avatar full path on SFTP server
+ */
+ @TableField(value = COL_AVATAR)
+ private String avatar;
+
+ /**
+ * Status. 1 - enabled, 2 - disabled
+ */
+ @TableField(value = COL_STATUS)
+ private Byte status;
+
+ /**
+ * Created by
+ */
+ @TableField(value = COL_CREATED_BY, fill = INSERT)
+ private Long createdBy;
+
+ /**
+ * Created time
+ */
+ @TableField(value = COL_CREATED_TIME, fill = INSERT)
+ private Date createdTime;
+
+ /**
+ * Modified by
+ */
+ @TableField(value = COL_MODIFIED_BY, fill = UPDATE)
+ private Long modifiedBy;
+
+ /**
+ * Modified time
+ */
+ @TableField(value = COL_MODIFIED_TIME, fill = UPDATE)
+ private Date modifiedTime;
+
+ /**
+ * Delete flag.
+ */
+ @TableField(value = COL_DELETED, fill = INSERT)
+ private Byte deleted;
+
+ public static final String TABLE_NAME = "user";
+
+ public static final String COL_ID = "id";
+
+ public static final String COL_USERNAME = "username";
+
+ public static final String COL_EMAIL = "email";
+
+ public static final String COL_CELLPHONE = "cellphone";
+
+ public static final String COL_PASSWORD = "password";
+
+ public static final String COL_FULL_NAME = "full_name";
+
+ public static final String COL_BIRTHDAY = "birthday";
+
+ public static final String COL_GENDER = "gender";
+
+ public static final String COL_AVATAR = "avatar";
+
+ public static final String COL_STATUS = "status";
+
+ public static final String COL_CREATED_BY = "created_by";
+
+ public static final String COL_CREATED_TIME = "created_time";
+
+ public static final String COL_MODIFIED_BY = "modified_by";
+
+ public static final String COL_MODIFIED_TIME = "modified_time";
+
+ public static final String COL_DELETED = "deleted";
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/persistence/UserRole.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/persistence/UserRole.java
new file mode 100644
index 00000000..0d4907a2
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/entity/persistence/UserRole.java
@@ -0,0 +1,42 @@
+package com.jmsoftware.maf.authcenter.user.entity.persistence;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * User-role Relation. Roles that users have.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/29/2021 12:09 PM
+ */
+@Data
+@TableName(value = UserRole.TABLE_NAME)
+public class UserRole {
+ /**
+ * The primary key
+ */
+ @TableId(value = COL_ID, type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * The primary key of user
+ */
+ @TableField(value = COL_USER_ID)
+ private Long userId;
+
+ /**
+ * The primary key of role
+ */
+ @TableField(value = COL_ROLE_ID)
+ private Long roleId;
+
+ public static final String TABLE_NAME = "user_role";
+
+ public static final String COL_ID = "id";
+
+ public static final String COL_USER_ID = "user_id";
+
+ public static final String COL_ROLE_ID = "role_id";
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.java
index f83928e9..e7a22b9b 100644
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.java
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.java
@@ -1,75 +1,17 @@
package com.jmsoftware.maf.authcenter.user.mapper;
-import com.jmsoftware.maf.authcenter.user.entity.UserPersistence;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jmsoftware.maf.authcenter.user.entity.persistence.User;
import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
/**
*
UserMapper
*
* Mapper of UserPersistence.(UserPersistence)
*
- * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
* @date 5 /10/20 12:17 PM
*/
@Mapper
-public interface UserMapper {
- /**
- * Select by id user persistence.
- *
- * @param id the id
- * @return the user persistence
- */
- UserPersistence selectById(Long id);
-
- /**
- * Select all by limit list.
- *
- * @param offset the offset
- * @param limit the limit
- * @return the list
- */
- List selectAllByLimit(@Param("offset") int offset, @Param("limit") int limit);
-
- /**
- * Query all list.
- *
- * @param userPersistence the user persistence
- * @return the list
- */
- List selectAll(UserPersistence userPersistence);
-
- /**
- * Insert int.
- *
- * @param userPersistence the user persistence
- * @return the int
- */
- int insert(UserPersistence userPersistence);
-
- /**
- * Update int.
- *
- * @param userPersistence the user persistence
- * @return the int
- */
- int update(UserPersistence userPersistence);
-
- /**
- * Delete by id int.
- *
- * @param id the id
- * @return the int
- */
- int deleteById(Long id);
-
- /**
- * Select user by username or email user persistence.
- *
- * @param loginToken the login token
- * @return the user persistence
- */
- UserPersistence selectUserByUsernameOrEmail(String loginToken);
+public interface UserMapper extends BaseMapper {
}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.java
new file mode 100644
index 00000000..597b49c9
--- /dev/null
+++ b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.java
@@ -0,0 +1,16 @@
+package com.jmsoftware.maf.authcenter.user.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jmsoftware.maf.authcenter.user.entity.persistence.UserRole;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * UserRoleMapper
+ *
+ * Mapper of user_role.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/4/2021 1:24 PM
+ */
+@Mapper
+public interface UserRoleMapper extends BaseMapper {
+}
diff --git a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/remote/UserRemoteApiController.java b/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/remote/UserRemoteApiController.java
deleted file mode 100644
index 8536ef86..00000000
--- a/auth-center/src/main/java/com/jmsoftware/maf/authcenter/user/remote/UserRemoteApiController.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.remote;
-
-import com.jmsoftware.maf.authcenter.user.service.UserService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenPayload;
-import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse;
-import com.jmsoftware.maf.common.domain.authcenter.user.SaveUserForRegisteringPayload;
-import com.jmsoftware.maf.common.domain.authcenter.user.SaveUserForRegisteringResponse;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.validation.Valid;
-
-/**
- *