내가 설정해둔 spring의 암호화 방법은 bCrypt이다.

 //MvcConfig
 @Bean(name = "bCryptPasswordEncoder")
  public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

 

초기 admin 계정을 넣을 때 비밀번호를 어떻게 찾을까?

https://www.devglan.com/online-tools/bcrypt-hash-generator

위의 사이트에서 text를 넣고 rounds를 선택해 Hash를 누르면 저절로 암호화된다.

이 암호문을 data.sql에 알맞은 위치에 넣고 실행시키면 admin 계정 비밀번호가 잘 저장되어 있을 것이다.

 

더 자세한 내용은

https://jusths.tistory.com/158

 

비밀번호 안전보관: bcrypt 를 알아보자

개요 사용자의 비밀번호를 그대로 보관하는 것은 위험하다. 비밀번호 보관에 특화된 bcrypt 를 알아보자. 참고링크 - 링크: https://auth0.com/blog/hashing-in-action-understanding-bcrypt/ - 링크: https://d2...

jusths.tistory.com

 

spring을 처음 실행시킬 때 초기 데이터를 넣어주기 위함이다.

 

  • application.yml 또는 application-local.yml
spring:
	datasource:
    	initialization-mode: always

처음에 이 상태로 실행시킨다.

 

  • data.sql

 위와 같이 data.sql 파일을 만들고 초기 데이터에 대한 SQL문을 넣는다.

 

위의 두개 설정을 마치고 실행시키면 DB에 초기값이 들어간다.

이후에 yml파일의 initialization-mode의 속성을 never로 바꾸어준다!

Intelli J에서 실행은 되지만 크롬 브라우저에서 들어가려고 하니.. 오류가 뜬다!

 

해결방법!

  • 주소를 https:// 에서 http://로 바꿔서 접속한다

 

❗ 너무 간단해서 오히려 화가난다.. ❗

❗ http와 https 사용법도 나중에 정리해야지.. ❗

'Web > Spring' 카테고리의 다른 글

[bcrypt] password 암호화  (0) 2021.08.10
[DB] 초기 데이터 삽입  (0) 2021.08.10
[Login구현] 권한부여(Role)  (0) 2021.08.10
[Login구현] 사용자 등록하기(Register)  (0) 2021.08.10
[Login구현] login-logout구현(setting)  (0) 2021.08.10

Role 사용을 해보자

내 프로젝트의 경우 ADD버튼이 admin으로 로그인했을 때만 나타나야 한다.

 

  • Role
@Getter
@AllArgsConstructor
public enum Role {
  ROLE_ADMIN("관리자", RoleBase.ADMINISTRATOR),
  ROLE_USER("사용자", RoleBase.USER);

  private String text;
  private RoleBase roleBase;

  public static List<Role> findByRoleBase(RoleBase roleBase) {
    return Arrays.stream(Role.values()).filter(p -> p.getRoleBase().equals(roleBase))
        .collect(Collectors.toList());
  }
}

일단 role은 ROLE_ADMIN과 ROLE_USER로 설정

DB에 admin 계정을 하나 넣어준다.(이를 처음 실행할 때 자동으로 넣어주도록 data.sql 파일을 생성해 넣어줘야 하는데 아직 구현하지 않았다.. 현재는 수동으로..!)

뒤에 User에 맞춰서 수동으로 넣어준다.

 

  • add버튼 관련
<html lang="ko" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<!--      admin-->
      <a class="addButton" th:text="|ADD|" th:href="|@{/project/edit}|" sec:authorize="hasRole('ROLE_ADMIN')"></a>

저렇게 설정하면 admin계정으로 로그인하면 add버튼이 보이고 logout 하면 보이지 않는다.

 

❗ 추가적으로 아예 관리자 대시보드를 만들려면 Controller에 어노테이션을 넣어준다. ❗

@Secured("ROLE_ADMIN")

그러면 해당 controller가 작동할 때는 admin계정으로 로그인했을 때이다.

화면 구성(resources/templates/auth)

  • register.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>register</title>
</head>
<body>
<form method="post" th:action="@{/auth/save}" th:object="${user}">
  <!--  th:with="Role=${T(com.example.loginpractice.enumerate.Role)}"-->
  <div class="container" style="padding: 15px">
    <div class="insert">
      <input th:field="*{id}" type="hidden"/>
      <div>
        <h2>회원가입 양식</h2>
        <div>
          <div class="col1">이름</div>
          <div class="col2"><input type="text" name="name" maxlength="5" th:field="*{name}"></div>
        </div>
        <div>
          <label class="col1" th:for="*{username}" th:text="|아이디|"><span
              style="color: #ff1034;"> *</span></label>
          <div class="col2">
            <input type="text" name="username" maxlength="10" th:field="*{username}">
            <button type="button" th:onclick="check()" id="checkUsername">중복확인</button>
          </div>
        </div>
        <div>r
          <div class="col1">비밀번호</div>
          <div class="col2">
            <input type="password" th:field="*{password}">
          </div>
        </div>
      </div>
    </div>
    <div class="create" style="padding-top: 10px">
      <button type="button" th:onclick="|location.href='@{/auth/login}'|">가입취소</button>
      <button type=" submit">회원가입</button>
    </div>
  </div>
</form>
<script th:inline="javascript">
  function check() {
    var username = $('#username').val();
    $.ajax({
      url: '/auth/username/check',
      type: 'POST',
      dataType: 'text',
      contentType: 'text/plain; charset=utf-8;',
      data: username,

      success: function (data) {
        if (data == 0) {
          console.log("아이디 없음");
          alert("사용하실 수 있는 아이디입니다.");
        } else {
          console.log("아이디 있음");
          alert("중복된 아이디가 존재합니다.");
        }
      },
      error: function () {
      }
    });
  }
</script>
</body>
</html>

간단하게 아이디, 비밀번호, 사용자 이름 폼을 사용, 아이디 중복확인 기능도 존재

 

  • AuthController
@Controller
@RequiredArgsConstructor
@RequestMapping("/auth")
public class AuthController {

  @NonNull
  private final UserService userService;
  @NonNull
  private final SmartValidator validator;
  
   @RequestMapping("/register")
  public String registerSelect() {
    return "auth/register-select";
  }

  @RequestMapping("/register/{role}")
  public String registerUser(Model model, @PathVariable(name = "role") Role role) {
    User user = new User();
    user.setRole(role);
    model.addAttribute("user", user);
//    model.addAttribute("passwordRuleMessage", PasswordUtil.getPasswordRuleMessage());
    return "auth/register";
  }

  @PostMapping("/save")
  public String save(Model model, @ModelAttribute User user, BindingResult result,
      RedirectAttributes redirectAttr) {

    user.setRole(Role.ROLE_USER);
//    boolean isUser = user.getRole().equals(Role.ROLE_USER) ? true : false;

    validator.validate(user, result, Default.class);

    if (!result.hasErrors()) {
      try {
        userService.save(user);
        redirectAttr.addFlashAttribute("message", "회원가입 성공");
        return "redirect:/auth/login";
      } catch (UserPasswordValidationException e) {
        e.printStackTrace();
      }
    }
//    model.addAttribute("passwordRuleMessage", PasswordUtil.getPasswordRuleMessage());
    return "auth/register";
  }
  
    @ResponseBody
  @GetMapping("/username/check")
  public ResponseEntity<HttpStatus> checkUsername(@RequestParam("username") String username) {
    if (userService.existsByUsername(username)) {
      return ResponseEntity.status(HttpStatus.CONFLICT).build();
    }
    return ResponseEntity.ok().build();
  }

  @ResponseBody
  @GetMapping("/name/check")
  public ResponseEntity<HttpStatus> checkName(@RequestParam("name") String name) {
    if (userService.existsByName(name)) {
      return ResponseEntity.status(HttpStatus.CONFLICT).build();
    }
    return ResponseEntity.ok().build();
  }
  }

사용자를 저장한다.

 

위와 같이 구현하면 사용자 등록에 성공할 수 있다..!

 

❗ 아직 find-account는 구현을 하지 못했다, 다음 포스팅은 권한 부여에 대해 얘기해보려 한다. ❗

login을 위한 setting

  • pom.xml
<!--    security-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
      <groupId>org.thymeleaf.extras</groupId>
      <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    </dependency>

 

  • domain-User
@Getter
@Setter
@Entity
@Table(name = "user", indexes = {@Index(columnList = "username"), @Index(columnList = "name"),
    @Index(columnList = "role"), @Index(columnList = "enabled"), @Index(columnList = "removed")})
@NoArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class User implements UserDetails {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @EqualsAndHashCode.Include
  private Integer id;

  @Column(nullable = false, insertable = false, updatable = false, columnDefinition = "datetime default CURRENT_TIMESTAMP")
  @DateTimeFormat(pattern = DateUtil.PATTERN_YMDHM)
  private LocalDateTime createDate;   //생성일시

  @Size(min = 2, max = 32)
  @Column(unique = true, nullable = false, updatable = false)
  private String username;

  @Size(min = 2, max = 8)
  @Column(nullable = false)
  private String name;

  @Column(nullable = false)
  @JsonIgnore
  private String password;

  @Enumerated(EnumType.STRING)
  @Column(nullable = false, updatable = false, columnDefinition = "varchar(50)")
  private Role role;

  @JsonIgnore
  @DateTimeFormat(pattern = DateUtil.PATTERN_YMD)
  @Column(columnDefinition = "date default CURRENT_TIMESTAMP")
  private LocalDate lastPasswordChangeDate = LocalDate.now();

  // 화면에서 추가인지 수정인지 여부를 보여주기 위함
  @Transient
  @JsonIgnore
  private boolean saved = false;

  @PostLoad
  private void postLoad() {
    this.saved = true;
  }

  @DateTimeFormat(pattern = DateUtil.PATTERN_YMD)
  private LocalDate expireDate;   //계정 만료일(null은 만료없음)

  @JsonIgnore
  @Column(columnDefinition = "bit(1) default 1", nullable = false)
  private boolean enabled = true;

  @JsonIgnore
  @Column(columnDefinition = "bit(1) default 0", nullable = false)
  private boolean locked = false;

  @JsonIgnore
  @Column(columnDefinition = "bit(1) default 0", nullable = false, insertable = false, updatable = false)
  private boolean superUser = false;

  @JsonIgnore
  @Column(columnDefinition = "bit(1) default 0", nullable = false, insertable = false)
  private boolean removed = false;

  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    List<GrantedAuthority> authorities = new ArrayList<>(0);
    authorities.add(new SimpleGrantedAuthority(role.name()));
    return authorities;
  }

  /**
   * 신규 사용자이거나 비밀번호 란에 비밀번호를 입력한 경우 비밀번호 유효성 검사 필요
   */
  public boolean hasPasswordChanged() {
    try {
      return !password.isEmpty() || id == null;
    } catch (Exception e) {

    }
    return false;
  }

  @JsonIgnore
  @Override
  public boolean isCredentialsNonExpired() {
    return true;
  }

  @JsonIgnore
  @Override
  public boolean isAccountNonExpired() {
//    if (expireDate != null) {
//      return expireDate.isAfter(LocalDate.now());
//    }
    return true;
  }

  @JsonIgnore
  @Override
  public boolean isAccountNonLocked() {
    return !locked && !removed;
  }

  @JsonIgnore
  @Override
  public boolean isEnabled() {
    return enabled && !removed;
  }

//  @JsonIgnore
//  public boolean hasRole(Role role) {
//    return this.role.equals(role);
//  }
}

 

  • domain-Certification
@Getter
@Setter
@Entity
@Table(name = "certification", indexes = {@Index(columnList = "phone")})
@NoArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Certification {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @EqualsAndHashCode.Include
  private Integer id;

  @Size(min = 12, max = 13)
  @NotNull
  private String phone;

  @Size(min = 6, max = 6)
  @NotNull
  private String authNumber;

  @JsonIgnore
  @Column(columnDefinition = "bit(1) default 0", nullable = false)
  private boolean certified = false;

  @JsonFormat(pattern = DateUtil.PATTERN_YMDHM)
  @DateTimeFormat(pattern = DateUtil.PATTERN_YMD)
  private LocalDateTime expireDate = LocalDateTime.now().plusMinutes(3);   //계정 만료일(null은 만료없음)
}

 

  • enumerate
// RoleBase
@Getter
@AllArgsConstructor
public enum RoleBase {
  ADMINISTRATOR("관리자"),
  USER("사용자");

  private String text;
}

//Role
@Getter
@AllArgsConstructor
public enum Role {
  ROLE_ADMIN("관리자", RoleBase.ADMINISTRATOR),
  ROLE_USER("사용자", RoleBase.USER);

  private String text;
  private RoleBase roleBase;

  public static List<Role> findByRoleBase(RoleBase roleBase) {
    return Arrays.stream(Role.values()).filter(p -> p.getRoleBase().equals(roleBase))
        .collect(Collectors.toList());
  }

}

❗ role을 사용하는 이유는 admin을 위해서!! 권한을 부여해줄 예정 ❗

 

  • config-SecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  private static final int TOKEN_VALIDITY_TIME = 604800;

  @NonNull
  private final BCryptPasswordEncoder bCryptPasswordEncoder;
  @NonNull
  private final UserService userService;

  @Bean
  public FilterRegistrationBean<Filter> getSpringSecurityFilterChainBindedToError(
      @Qualifier("springSecurityFilterChain") Filter springSecurityFilterChain) {
    FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
    registration.setFilter(springSecurityFilterChain);
    registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
    return registration;
  }

  @Bean
  public AuthenticationFailureHandler customAuthenticationFailureHandler() {
    return new CustomAuthenticationHandler();
  }

  @Bean
  public AuthenticationSuccessHandler customAuthenticationSuccessHandler() {
    return new CustomAuthenticationHandler();
  }

  @Bean
  public LoginUrlAuthenticationEntryPoint ajaxAwareAuthenticationEntryPoint() {
    return new AjaxAwareAuthenticationEntryPoint(SpringSecurity.LOGIN_URL);
  }

  @Bean
  public AccessDeniedHandler customAccessDeniedHandler() {
    return new CustomAccessDeniedHandler();
  }

  /**
   * 유저 DB의 DataSource와 Query 및 Password Encoder 설정.
   */
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder);
  }

  /**
   * Spring Security에서 인증받지 않아도 되는 리소스 URL 패턴을 지정해 줍니다.
   */
  @Override
  public void configure(WebSecurity web) {
    web.ignoring().antMatchers("/static/**");
  }

  @Bean
  public CorsConfigurationSource corsConfigurationSource() {
    final CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Collections.singletonList("*"));
    configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
    // setAllowCredentials(true) is important, otherwise:
    // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
    configuration.setAllowCredentials(true);
    // setAllowedHeaders is important! Without it, OPTIONS preflight request
    // will fail with 403 Invalid CORS request
    configuration.setAllowedHeaders(Collections.singletonList("Authorization"));
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
  }

  /**
   * Spring Security에 의해 인증받아야 할 URL 또는 패턴을 지정해 줍니다.
   */
  @Override
  protected void configure(HttpSecurity http) throws Exception {

    http.headers().frameOptions().sameOrigin()
        .and().csrf().disable().authorizeRequests()
        .antMatchers("/admin/**","/mypage/**","/comment/**").authenticated()
        .anyRequest().permitAll()
        .and().formLogin().loginPage(SpringSecurity.LOGIN_URL)
        .loginProcessingUrl(SpringSecurity.LOGIN_PROCESS_URL)
        .successHandler(customAuthenticationSuccessHandler())
        .failureHandler(customAuthenticationFailureHandler())
        .usernameParameter(SpringSecurity.PARAM_USERNAME)
        .passwordParameter(SpringSecurity.PARAM_PASSWORD)
        .and().logout()
        .logoutRequestMatcher(new AntPathRequestMatcher(SpringSecurity.LOGOUT_URL))
        .logoutSuccessUrl(SpringSecurity.LOGIN_URL)
        .and().exceptionHandling().authenticationEntryPoint(ajaxAwareAuthenticationEntryPoint())
        .accessDeniedHandler(customAccessDeniedHandler())
        .and().rememberMe().disable();
  }
}

 

  • config-MvcConfig
  @Bean(name = "bCryptPasswordEncoder")
  public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

❗ MvcConfig에 @Bean으로 추가를 해야 사용이 가능하다!! ❗

 

  • config-PasswordConfig
@Getter
@Setter
@Configuration
@ConfigurationProperties("password")
@PropertySources({@PropertySource(value = "classpath:/config/password.properties")})
public class PasswordConfig {

  private Validation validation;

  @Getter
  @Setter
  @Configuration
  @ConfigurationProperties("herbnet.password-validation")
  public static class Validation {

    private int length;
    private boolean specialCharacters;
    private boolean upperCases;
    private boolean numbers;
    private int maxAttemptsCount;
    private int changeCycle;
  }

}

❗ password.properties는 취향 것.. ❗

알아서 설정

  • config-기타
//AjaxAwareAuthenticationEntryPoint
public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {

  public AjaxAwareAuthenticationEntryPoint(String loginUrl) {
    super(loginUrl);
  }

  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response,
      AuthenticationException authException) throws IOException, ServletException {
    String ajaxHeader = request.getHeader("X-Requested-With");
    boolean isAjax = "XMLHttpRequest".equals(ajaxHeader);

    if (isAjax) {
      response
          .sendError(HttpServletResponse.SC_UNAUTHORIZED, "Ajax Request Denied (Session Expired)");
    } else {
      super.commence(request, response, authException);
    }
  }
}

//CustomAuthenticationHandler
public class CustomAuthenticationHandler
    implements AuthenticationSuccessHandler, AuthenticationFailureHandler {

  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
      Authentication auth) throws IOException {

    response.sendRedirect(request.getContextPath() + SpringSecurity.LOGIN_SUCCESS_URL);
  }

  @Override
  public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
      AuthenticationException exception) throws IOException, ServletException {

    String username = request.getParameter("username");
    String dispatcherURL = SpringSecurity.LOGIN_URL;

    request.setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);
    request.setAttribute("SPRING_SECURITY_LAST_USERNAME", username);
    request.setAttribute("username", username);
    request.setAttribute("error", getErrorMessage(exception));
    request.getRequestDispatcher(dispatcherURL).forward(request, response);
  }

  /**
   * Spring Security 가 반환하는 에러 메시지 얻어옴
   *
   * @return 에러메시지
   */
  private String getErrorMessage(AuthenticationException exception) {

    String error;
    if (exception instanceof AccountExpiredException) {
      error = "사용 기간이 만료된 계정입니다.";
    } else if (exception instanceof BadCredentialsException) {
      error = "아이디 또는 비밀번호를 확인해주시기 바랍니다.";
    } else if (exception instanceof LockedException) {
      error = "로그인 반복 실패 또는 관리자에 의해 잠겨있는 계정입니다.\n관리자에게 문의하세요.";
    } else if (exception instanceof InternalAuthenticationServiceException) {
      error = "존재하지 않는 계정입니다.";
    } else if (exception instanceof DisabledException) {
      error = "승인되지 않은 계정입니다. 관리자의 승인을 기다려주세요.";
    } else if (exception instanceof CredentialsExpiredException) {
      error = "만료된 비밀번호 입니다.";
    } else {
      error = exception.getLocalizedMessage();
    }

    return error;
  }
}

//CustomAccessDeniedHandler
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

  @Override

  public void handle(HttpServletRequest request, HttpServletResponse response,
      AccessDeniedException accessDeniedException) throws IOException {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    if (authentication instanceof AnonymousAuthenticationToken) {
      response.sendRedirect(request.getContextPath() + SpringSecurity.LOGIN_URL);
    }
  }
}

 

  • util-ApplicationContextProvider
public class ApplicationContextProvider implements ApplicationContextAware {

  private static ApplicationContext applicationContext;

  public static <T> T getEnvironmentProperty(String key, Class<T> targetClass, T defaultValue) {
    if (key == null || targetClass == null) {
      throw new NullPointerException();
    }

    T value = null;
    if (applicationContext != null) {
      value = applicationContext.getEnvironment().getProperty(key, targetClass, defaultValue);
    }
    return value;
  }

  public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
    ApplicationContextProvider.applicationContext = applicationContext;
  }
}

 

  • util-LoginAuth
public class LoginAuth {

  /* 계정 정보 */
  public static final String PASSWORD_SPECIAL_REGEXP = "(?=.*[!@#$%^&*()\\-_=+\\\\\\|\\[\\]{};:\\'\",.<>\\/?])";
  public static final String PASSWORD_UPPER_REGEXP = "(?=.*[A-Z])";
  public static final String PASSWORD_NUMBER_REGEXP = "(?=.*\\d)";
}

 

  • util-PasswordUtil
@UtilityClass
public class PasswordUtil {

  public static boolean isValidPassword(String password) {
    int length = ApplicationContextProvider
        .getEnvironmentProperty("validation.length", Integer.class, 0);
    boolean specialCharacters = ApplicationContextProvider
        .getEnvironmentProperty("validation.special-characters", Boolean.class,
            false);
    boolean upperCases = ApplicationContextProvider
        .getEnvironmentProperty("validation.upper-cases", Boolean.class, false);
    boolean numbers = ApplicationContextProvider
        .getEnvironmentProperty("validation.numbers", Boolean.class, false);

    String baseRegExp = "";
    String specialRegExp = "";
    String upperRegExp = "";
    String numberRegExp = "";

    if (specialCharacters) {
      specialRegExp = LoginAuth.PASSWORD_SPECIAL_REGEXP;
    }
    if (upperCases) {
      upperRegExp = LoginAuth.PASSWORD_UPPER_REGEXP;
    }
    if (numbers) {
      numberRegExp = LoginAuth.PASSWORD_NUMBER_REGEXP;
    }

    baseRegExp =
        "^" + specialRegExp + upperRegExp + numberRegExp
            + "[A-Za-z\\d!@#$%^&*()\\-_=+\\\\\\|\\[\\]{};:\\'\",.<>\\/?]{" + length + ",}";

    if (!StringUtils.isBlank(password) && password.matches(baseRegExp)) {
      return true;
    }
    return false;
  }

  public static String getPasswordRuleMessage() {
    String message = "비밀번호는 ";
    List<String> ruleIncluded = new ArrayList<>();

    int length = ApplicationContextProvider
        .getEnvironmentProperty("validation.length", Integer.class, 0);
    boolean specialCharacters = ApplicationContextProvider
        .getEnvironmentProperty("validation.special-characters", Boolean.class,
            false);
    boolean upperCases = ApplicationContextProvider
        .getEnvironmentProperty("validation.upper-cases", Boolean.class, false);
    boolean numbers = ApplicationContextProvider
        .getEnvironmentProperty("validation.numbers", Boolean.class, false);

    ruleIncluded.add("영문 소문자");

    if (specialCharacters) {
      ruleIncluded.add("특수문자");
    }

    if (upperCases) {
      ruleIncluded.add("영문 대문자");
    }

    if (numbers) {
      ruleIncluded.add("숫자");
    }

    if (!ruleIncluded.isEmpty()) {
      message += String.format("%s를 포함하여 ", StringUtils.join(ruleIncluded, ", "));
    }

    message += String.format("%d자리 이상으로 구성되어야 합니다.", length);

    return message;
  }
}

 

  • util-SpringSecurity
    public class SpringSecurity {
      public static final String LOGIN_URL = "/auth/login";
      public static final String LOGIN_PROCESS_URL = "/auth/login/process";
      public static final String LOGIN_SUCCESS_URL = "/";
      public static final String LOGOUT_URL = "/auth/logout";
      public static final String PARAM_USERNAME = "username";
      public static final String PARAM_PASSWORD = "password";
      public static final String PARAM_REMEMBER = "remember-me";
      public static final String KEY_REMEMBER = "알아서";
    }​

 

  • exception-UserPasswordValidationException
@SuppressWarnings("serial")
public class UserPasswordValidationException extends Exception {

  @Override
  public String getMessage() {
    return "비밀번호 규칙이 일치하지 않습니다";
  }
}

 

  • exception-DataNotFoundException
@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class DataNotFoundException extends HttpClientErrorException {

  public DataNotFoundException() {
    super(HttpStatus.NOT_FOUND, "데이터를 찾을 수 없습니다.");
  }

  public DataNotFoundException(String message) {
    super(HttpStatus.NOT_FOUND, message);
  }
}

 

 

+ Recent posts