スプリングセーフ3)-JWTログイン方式
36351 ワード
Spring BootでセッションベースのSpringセキュリティを実装します~!
ダウンジャケットの整理本を参考にしてください!
https://github.com/namusik/TIL-SampleProject/blob/main/Spring%20Boot/%EC%8A%A4%ED%94%84%EB%A7%81%20%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0/%EC%8A%A4%ED%94%84%EB%A7%81%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%20%EA%B0%9C%EB%85%90.md
https://github.com/namusik/TIL-SampleProject/tree/main/Spring%20Boot/%EC%8A%A4%ED%94%84%EB%A7%81%20%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0/%EC%8A%A4%ED%94%84%EB%A7%81%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%20%EC%84%B8%EC%85%98%EB%B0%A9%EC%8B%9D
(ただしサーバーがシャットダウンするとデータベースも消えます!)
スプリングのセキュリティ依存性を追加すると、WebSecurityConfigurator Adapterクラスが実行されます.
ここではセキュリティの初期化と設定を担当します.
WebSecurityConfigurator Adapterを継承するカスタム構成を個人プロジェクトに基づいて作成すればよい.
@EnableWebSecurity
h 2-consoleページを追加して、不正な使用のために使用します.
HttpSecurity
!!重要なのは、HttpSecurityオブジェクトを通してスプリングの安全に各種設定をすることです!!
URLアクセス権の設定
プロジェクトのユーザークラス(メンバー情報)をフィールドにします.
それぞれの項目に応じて、DBで会員情報を検索する部分をカスタマイズします.
上で作成したUserDetailsImplを返します.
ドキュメンタリーではROLEの形態とされているので、最初からこのような形で作ったほうがいいです.
ここで注意したいのは、対応する権限を持つユーザーのみがアクセスできるように@Secured(「ROLE ADMIN」)がメソッドに追加されていることです.
管理者として会員登録に必要なパスワードは、UserService 26行目にあることに注意してください.
メソッドのパラメータから,@AuthenticationPrincipalがある.
前述したように、@EnableWebSecurity宣言により有効になります.
現在のセッションにログインしているユーザーに対してUserDetailsImplをロードできます.
'/frobidden'URIは次のとおりです.
http.exceptionHandling().accessDeniedPage("/forbidden"); 同じでなければなりません.
それ以外にhtmlと例外処理の部分は上部のQuizhubリンクを参照してください.
https://webfirewood.tistory.com/115
https://daddyprogrammer.org/post/636/springboot2-springsecurity-authentication-authorization/
https://bcp0109.tistory.com/301
スプリング安全性の基本概念
ダウンジャケットの整理本を参考にしてください!
https://github.com/namusik/TIL-SampleProject/blob/main/Spring%20Boot/%EC%8A%A4%ED%94%84%EB%A7%81%20%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0/%EC%8A%A4%ED%94%84%EB%A7%81%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%20%EA%B0%9C%EB%85%90.md
ソースコード
https://github.com/namusik/TIL-SampleProject/tree/main/Spring%20Boot/%EC%8A%A4%ED%94%84%EB%A7%81%20%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0/%EC%8A%A4%ED%94%84%EB%A7%81%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%20%EC%84%B8%EC%85%98%EB%B0%A9%EC%8B%9D
作業環境
IntelliJ
Spring Boot
java 11
gradle
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
implementation 'org.springframework.boot:spring-boot-devtools'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
スプリングセキュリティ、h 2データベース、および時間軸依存性が追加されました.application.properties
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:springminiprojectdb
spring.datasource.username=sa
spring.datasource.password=
簡単なh 2をメンバー情報を保存するDBとして使用する.(ただしサーバーがシャットダウンするとデータベースも消えます!)
WebSecurityConfig
スプリングのセキュリティ依存性を追加すると、WebSecurityConfigurator Adapterクラスが実行されます.
ここではセキュリティの初期化と設定を担当します.
WebSecurityConfigurator Adapterを継承するカスタム構成を個人プロジェクトに基づいて作成すればよい.
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsServiceImpl userDetailsServiceImpl;
@Bean
public BCryptPasswordEncoder encoderPassword() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/h2-console/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//csfr 사용안함
http.csrf().disable();
//URL 인증여부 설정.
http.authorizeRequests()
.antMatchers( "/user/signup", "/", "/user/login", "/css/**").permitAll()
//@Secured("ROLE_ADMIN")으로 대체 .antMatchers("/api/admin").hasRole("ADMIN")
.anyRequest().authenticated();
//로그인 관련 설정.
http.formLogin()
.loginPage("/user/login")
.loginProcessingUrl("/user/login") //Post 요청
.defaultSuccessUrl("/")
.failureUrl("/user/login?error")
.permitAll();
//로그아웃 설정
http.logout()
.logoutUrl("/user/logout")
.logoutSuccessUrl("/");
//비인가자 요청시 보낼 Api URI
http.exceptionHandling().accessDeniedPage("/forbidden");
}
}
Annotation@EnableWebSecurity
Security 활성화 Annotation.
클릭해보면 @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class,
OAuth2ImportSelector.class,HttpSecurityConfiguration.class })이 달려서
해당 Class들을 실행시켜줌.
또한, @AuthenticationPrincipal을 통해 Authentication 객체 속에 있는 principal 필드 가져올 수 있음.
@EnableGlobalMethodSecurity(securedEnabled=true)Controller에 직접 @Secured("ROLE_ADMIN")을 쓸 수 있게 됨.
ここで待って!HttpSecurity permitAll()とWebSecurity ingnoring()の違いは何ですか?WebSecurity는 Spring Security Filter Chain을 아예 거치지 않기에
"인증", "인가" 모두 적용되지 않음. 또한, XSS에 대한 보호가 제공안됨.
HttpSecurity보다 우선 적용되기 때문에 두곳에 모두 설정해도 WebSecurity만 적용됨.
HttpSecurity는 "인증"을 무시함. Security Filter Chain을 거쳐서 요청이 들어옴.
WebSecurityh 2-consoleページを追加して、不正な使用のために使用します.
HttpSecurity
!!重要なのは、HttpSecurityオブジェクトを通してスプリングの安全に各種設定をすることです!!
URLアクセス権の設定
http.authorizeRequests()
.antMatchers( "/user/signup", "/", "/user/login", "/css/**").permitAll()
해당 URL에는 인증절차(로그인) 없이 접근허용
.antMathcers("/admin/**").hasAnyRole("ADMIN")
해당 URL에는 ADMIN레벨 권한을 가진 사용자만 접근허용
@Secured() 어노테이션으로 대체해주었음.
.anyRequest().authenticated();
나머지 URL은 모두 스프링시큐리티 인증을 거쳐야됨을 설정.
ログイン設定http.formLogin()
일반적인 로그인 방식, 로그인 Form페이지와 로그인 성공/실패 처리 등을 사용하겠다는 의미.
.loginPage("/user/login")
로그인 페이지로 넘어가는 Get 방식 Controller URI.
따로 설정해주지않으면 Default값인 "/login"로 설정되어있는 기본로그인페이지 제공됨.
.loginProcessUrl("/user/login") Post방식.
해당 Controller URI로 요청을 할 경우 자동으로 스프링시큐리티 로그인 인증과정이 시작되도록 설정.
.defaultSuccessUrl("/") Get방식
로그인 성공시 요청하는 Controller URI
설정하지 않는경우 "/"값이 defaultf로 설정됨.
.failureUrl("/user/login?error")
로그인 실패했을 때 요청하는 Controller URI
.permitAll()
로그인 과정은 당연히 로그인하기 전이므로 인증이 없이 진행허가.
ログアウトに関する設定http.logout()
.logoutURL("/user/logout")
시큐리티에서 미리 만들어둔 로그아웃로직을 사용하기 위해 URI를 정해줌.
.logoutSuccessUrl("/")
로그아웃 성공시 요청할 URI
ライセンスに関する設定http.exceptionHandling().accessDeniedPage("/forbidden");
권한이 없는 사용자가 특정페이지를 접근하려 할때 접근금지 페이지로 보내주기 위해.
UserDetailsImpl
public class UserDetailsImpl implements UserDetails {
//직접 정의한 User 클래스를 필도로 가지게 함.
private final User user;
//생성자를 통해 유지
public UserDetailsImpl(User user) {
this.user = user;
}
public User getUser() {
return user;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(user.getRole().toString());
return authorityList;
}
}
UserDeatilsクラスのUserDetailsImplを実装します.プロジェクトのユーザークラス(メンバー情報)をフィールドにします.
UserDetailsServiceImpl
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
//로그인할 때 들어온 username으로 DB에서 정보 찾기
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new CustomException(ErrorCode.NO_USER));
//UserDetailsImpl에서 정의한 생성자
return new UserDetailsImpl(user);
}
}
UserDetailsServiceのサービスクラスを実装します.それぞれの項目に応じて、DBで会員情報を検索する部分をカスタマイズします.
上で作成したUserDetailsImplを返します.
UserRoleEnum
@Getter
public enum UserRoleEnum {
//spring security가 제공하는 ROLE 네이밍 정책이 <ROLE_권한>이므로 맞춰서 작성해준다.
ROLE_ADMIN("관리자"), ROLE_MEMBER("일반사용자");
private String description;
UserRoleEnum(String description) {
this.description = description;
}
}
メンバー権限のEnumクラス.ドキュメンタリーではROLEの形態とされているので、最初からこのような形で作ったほうがいいです.
AdminPageController
@Controller
public class AdminPageController {
@GetMapping("/api/admin")
@Secured("ROLE_ADMIN")
public String adminPage(@AuthenticationPrincipal UserDetailsImpl userDetails) {
return "admin";
}
}
コントローラは、管理者のみがアクセスできる管理者ページに移動できます.ここで注意したいのは、対応する権限を持つユーザーのみがアクセスできるように@Secured(「ROLE ADMIN」)がメソッドに追加されていることです.
管理者として会員登録に必要なパスワードは、UserService 26行目にあることに注意してください.
MainPageController
@Controller
public class MainPageController {
@GetMapping("/")
public String mainPage(@AuthenticationPrincipal UserDetailsImpl userDetails, Model model) {
if (userDetails != null) {
User user = userDetails.getUser();
System.out.println(user.getRole().getDescription());
model.addAttribute("user", user);
} else {
model.addAttribute("user", "");
}
return "index";
}
}
ホームページのコントローラに入ります.メソッドのパラメータから,@AuthenticationPrincipalがある.
前述したように、@EnableWebSecurity宣言により有効になります.
現在のセッションにログインしているユーザーに対してUserDetailsImplをロードできます.
ForbiddenPageController
@Controller
public class ForbiddenPageController {
@GetMapping("/forbidden")
public String forbiddenPage() {
return "forbidden";
}
}
不正なページにアクセスしたときに送信されるコントローラ.'/frobidden'URIは次のとおりです.
http.exceptionHandling().accessDeniedPage("/forbidden"); 同じでなければなりません.
残り
それ以外にhtmlと例外処理の部分は上部のQuizhubリンクを参照してください.
実行結果
リファレンス
https://webfirewood.tistory.com/115
https://daddyprogrammer.org/post/636/springboot2-springsecurity-authentication-authorization/
https://bcp0109.tistory.com/301
Reference
この問題について(スプリングセーフ3)-JWTログイン方式), 我々は、より多くの情報をここで見つけました https://velog.io/@rainbowweb/스프링시큐리티-3-JWT-로그인-방식テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol