최근 프로젝트에서 문제를 겪었습니다. 프론트 엔드와 백엔드가 분리되고, 프론트 엔드는 VUE와 함께 수행되며, 모든 데이터 요청은 vue-Resource를 사용하며, 양식이 사용되지 않으므로 데이터 상호 작용은 JSON에서 사용하고 스프링 부팅을 사용하고 허가 검증은 스프링 보안을 사용합니다. Spring Security가 이전에 사용 되었기 때문에 페이지를 처리했으며 이번에는 AJAX 요청을 간단히 처리하여 발생하는 몇 가지 문제를 기록했습니다. 여기의 솔루션은 AJAX 요청에 적합 할뿐만 아니라 모바일 요청 확인도 해결합니다.
프로젝트를 만듭니다
우선, 우리는 스프링 부팅 프로젝트를 만들어야합니다. 이를 만들 때 웹, 스프링 보안, MySQL 및 MyBatis를 소개해야합니다 (데이터베이스 프레임 워크는 실제로 임의적이며 여기에 MyBatis를 사용합니다). 생성 후 종속성 파일은 다음과 같습니다.
<pectionency> <groupid> org.mybatis.spring.boot </groupid> <artifactid> mybatis-spring-boot-starter </artifactid> <3.1 </dependency> <pelection> <groupid> org.springframework.boot </groupid> <Artifactid> Spring-Boot-Starter-Security </artifactid> </fectionency> <pectomency> <groupid> org.springframework.boot </groupid> <tructid> spring-boot-starter-web </artifactid> </dependency> <groupid> mysql> <Artifactid> mysql-connector-java </artifactid> <cope> 런타임 </scope> </spectency> <prection> <groupid> commons-codec </groupid> <trifactid> commons-codec </artifactid> <1.11 </version> </fectionency>
마지막 Commons-Codec 의존성은 수동으로 추가되었습니다. 이것은 MD5 메시지 소화를 생성하는 데 사용할 수있는 Apache의 오픈 소스 프로젝트입니다. 다음 텍스트로 비밀번호를 처리하겠습니다.
데이터베이스를 작성하고 구성하십시오
논리를 단순화하기 위해 다음과 같이 사용자 테이블, 역할 테이블 및 사용자 역할 협회 테이블과 같은 세 개의 테이블을 만들었습니다.
다음으로 Application.Properties에서 데이터베이스를 간단하게 구성해야합니다. 여기서 우리는 당신의 특정 상황에 따라 결정됩니다.
spring.datasource.url = jdbc : mysql : ///vueblogspring.datasource.username=RootSpring.datasource.Password=123
엔티티 클래스를 구성하십시오
여기서는 주로 사용자 클래스를 구성하는 것을 의미합니다. 여기서 사용자 클래스는 매우 특별하며 다음과 같이 사용자 데일 인터페이스를 구현해야합니다.
공개 클래스 사용자는 userDetails {private long id; 개인 문자열 사용자 이름; 개인 문자열 비밀번호; 개인 문자열 별명; 개인 부울 가능성; 개인 목록 <Brole> 역할; @override public boolean isaccountnonexpired () {return true; } @override public boolean isaccountnonlocked () {return true; } @override public boolean iscredentialsnonexpired () {return true; } @override public boolean isenabled () {return enabled; } @override public list <getedauthority> getAuthorities () {list <grantedauthority> 당국 = new ArrayList <> (); for (역할 역할 : 역할) {당국 .add (New SimplegrantEdauthority ( "role_" + roble.getName ())); } 반환 당국; } // getter/setter 생략 ...} userDetails 인터페이스를 구현 한 후이 인터페이스에는 구현 해야하는 몇 가지 방법이 있습니다. 부울을 반환하는 네 가지 방법은 모두 알려져 있고 알려져 있습니다. 활성화는 기간 계정이 활성화되어 있는지 여부를 나타냅니다. 이 필드는 내 데이터베이스에 존재합니다. 따라서 쿼리 결과에 따르면 다른 하나는 간단한 기간 동안 직접 반환합니다. GetAuthoriities 메소드는 현재 사용자의 역할 정보를 반환합니다. 사용자의 역할은 실제로 역할의 데이터입니다. 역할의 데이터는 <getedauthority> 목록으로 변환 된 다음 반환됩니다. 여기에 주목할 점이 있습니다. 데이터베이스에 저장 한 역할 이름은 모두 '슈퍼 관리자', '일반 사용자'등이므로 ROLE_ 와 같은 문자로 시작하지 않으므로 여기에 수동으로 ROLE_ 추가해야합니다.
역할 엔티티 클래스도 있습니다.이 클래스는 비교적 간단하며 데이터베이스의 필드에 따라 만들 수 있습니다. 나는 여기서 그것을 반복하지 않을 것입니다.
사용자 서비스를 만듭니다
여기서 사용자 서비스도 매우 특별하며 다음과 같이 userDetailsService 인터페이스를 구현해야합니다.
@ServicePublic Class userErvice는 userDetailsService {@autowired usermapper usermapper를 구현합니다. @autowired rolesmapper rolesmapper; @override public userDetails loadUserByUserName (String S)은 usernamenotfoundException {user user = usermpper.loadUserByUserName (s); if (user == null) {// NULL 리턴을 피하십시오. 여기에 값이 포함되지 않은 사용자 객체를 반환하면 후기 비밀번호 비교에서 확인이 실패합니다. } // 사용자의 역할 정보를 쿼리하고 사용자에게 반환합니다. 목록 <brole> roboles = rolesmapper.getRolesByUid (user.getId ()); user.setroles (역할); 리턴 사용자; }}userDetailsService 인터페이스를 구현 한 후 인터페이스에서 LoadUserByUserName 메소드, 즉 사용자 이름을 기반으로 사용자를 쿼리해야합니다. MyBatis의 두 개의 맵퍼가 여기에 주입되고 UsermPaper는 사용자를 쿼리하는 데 사용되며 ROLESMAPPER는 역할을 쿼리하는 데 사용됩니다. LoadUserByUserName 메소드에서 먼저 전달 된 매개 변수에 따라 사용자를 쿼리합니다 (매개 변수는 사용자가 로그인 할 때 입력 한 사용자 이름입니다). 찾은 사용자가 NULL 인 경우 usernamenotfoundException 예외를 직접 던질 수 있습니다. 그러나 처리의 편의를 위해 값이없는 사용자 객체를 반환했습니다. 이러한 방식으로 후속 비밀번호 비교 프로세스 중에 로그인이 실패한 것을 알 수 있습니다 (여기서는 비즈니스 요구에 따라 조정할 수 있음). 찾은 사용자가 NULL이 아닌 경우 사용자 ID에 따라 사용자의 역할을 쿼리하고 쿼리 결과를 사용자 객체에 넣습니다. 이 쿼리 결과는 사용자 객체의 getAuthoriitions 메소드에 사용됩니다.
보안 구성
보안 구성을 먼저 살펴본 다음 하나씩 설명하겠습니다.
@ConfigurationPublic 클래스 WebSecurityConfig는 WebSecurityConfigurerAdapter {@autowired userervice userervice를 확장합니다. @override Protected void configure (AuthenticationManagerBuilder Auth)는 예외를 {auth.userDetailsService (userervice) .PasswordEncoder (new passwordEncoder () {@override public string encode (chareverence charEdegecence) {return digestutils.md5digestasHex (charseverence.toString).); @param chared ext* @param s ciphertext* @return*/ @override public boolean matches (charseverence charedecence, string s) {return s.equals (digestutils.md5digestashex.tostring (). getBytes ()); } @override Protected Avoid Configure (httpsecurity http)는 예외를 {http.authorizeRequests () .AntMatchers ( "/admin/**"). hasrole ( "Super Admin") .AnyRequest (). 인증 된 후에 액세스합니다. in.and (). formlogin (). loginpage ( "/login_page"). successHandler (new AuthenticationSuccessHandler () {@override public void onauthenticationSuccess (httpservletRequest httpservletrequest, httpservletreponse httperponsevletr rongection, 인증) servletexception.setContentType. }) .failureHandler (New AuthenticationFailureHandler () {@Override public void OnauthenticationFailure (httpservletRequest httpservletrequest, httpservletResponse httpservletResponse, AuthicationException E). httppletresponse.setContentType (Application/JSON; charset = utf-8); }). LoginProcessingUrl ( "/login") .usernameparameter ( "username"). passwordParameter ( "password"). cermitAll (). (). logout (). csrf (). csrf (). disable (); } @override public void configure (Websecurity Web)는 예외 {web.ignoring (). Antmatchers ( "/reg"); }}이것이 우리 구성의 핵심입니다. 내 말을 들어주세요 :
1. 우선, 이것은 구성 클래스이므로 @Configuration 주석을 추가하십시오. 이것은 스프링 보안의 구성이므로 WebSecurityConfigurerAdapter를 상속해야합니다.
2. 방금 생성 된 사용자 서비스를 주입하면 나중에 사용할 것입니다.
3. Configure (AuthenticationManagerBuilder Auth) 메소드는 인증 메소드를 구성하고 Authentication Method를 구성하고 Auth.UserDetailsService () 메소드에서 사용자 서비스를 전달하는 데 사용됩니다. 따라서 사용자 서비스의 LoadUserByUserName 메소드는 사용자 로그를 기록 할 때 자동으로 호출됩니다. 비밀번호 코더가 선택 가능하거나 비밀번호를 작성하지 않기 때문입니다. 로그인 할 때 처리하기 위해서도 일반 텍스트 비밀번호도 필요하므로 PasswordEncoder를 추가했으며 PasswordEncoder를 추가 한 후 익명의 내부 클래스의 암호 에코 인더를 직접 새롭게 할 수 있습니다. 여기에 구현해야 할 두 가지 방법이 있으며 이름을 보면서 메소드의 의미를 알 수 있습니다. 첫 번째 메소드는 분명히 일반 텍스트를 암호화합니다. 여기서는 MD5 메시지 다이제스트를 사용합니다. 특정 구현 방법은 Commons-Codec 의존성에 의해 제공됩니다. 두 번째 메소드 일치는 비밀번호 비교, 두 개의 매개 변수, 첫 번째 매개 변수는 일반 텍스트 비밀번호이고 두 번째 매개 변수는 암호문입니다. 여기에서는 일반 텍스트를 암호화하고 암호 텍스트와 비교하면됩니다 (이에 관심이있는 경우 비밀번호에 소금을 계속 추가하는 것을 고려할 수 있습니다).
4. Configure (httpsecurity http)는 인증 규칙 등을 구성하는 데 사용됩니다. 승인 QuesseRquests 메소드는 인증 규칙 구성이 활성화되었음을 의미합니다. Antmatchers ( "/Admin/**"). Hasrole ( "Super Administrator")은 /admin/** 의 경로가 '슈퍼 관리자'역할을 가진 사용자가 액세스해야 함을 의미합니다. 인터넷에서 친구들은 해산법에 ROLE_ 추가할지 여부에 대해 질문을했습니다. 여기에 추가하지 마십시오. Hasauthority 메소드를 사용하는 경우 추가해야합니다. anyrequest (). authenticated ()는 액세스하기 전에 다른 모든 경로를 인증/로그인해야 함을 의미합니다. 다음으로 로그인 페이지를 login_page로 구성했으며 로그인 처리 경로는 /로그인이고 로그인 사용자 이름은 사용자 이름이며 비밀번호는 비밀번호입니다. 이러한 경로를 직접 액세스하도록 구성했으며 로그인 로그 아웃에 직접 액세스 할 수도 있고 마지막으로 CSRF를 닫을 수도 있습니다. SuccessHandler에서는 응답을 사용하여 성공적으로 로그인 한 JSON을 반환합니다. defaultsuccessurl을 사용하지 마십시오. defaultsuccessurl은 성공적으로 로그인 한 후에 만 리디렉션되는 페이지입니다. 동일한 이유도 실패 핸들러에도 사용됩니다.
5. 구성 (Websecurity Web) 메소드에서 일부 필터링 규칙을 구성 했으므로 자세한 내용은 없습니다.
6. 또한 /images/** , /css/** 및 /js/** 와 같은 정적 파일의 경우 기본값이 차단되지 않습니다.
제어 장치
마지막으로 다음과 같이 컨트롤러를 살펴 보겠습니다.
@RestControllerPublic Class LoginRegController {/** *이 페이지로 자동 점프하면 사용자가 로그인되지 않았다는 것을 의미하며 해당 프롬프트 * <p> *를 반환 할 수 있습니다. * <p> * 양식 로그인을 지원하려면이 방법에서 요청 유형을 판단하고 JSON 또는 HTML Page로 돌아갈지 여부를 결정할 수 있습니다. respbean loginpage () {return new respbean ( "error", "아직 로그인되지 않았으며 로그인하십시오!"); }} 전반적 으로이 컨트롤러는 비교적 간단합니다. Respbean은 간단한 JSON을 반환합니다. 여기에주의를 기울여야 할 것은 login_page 입니다. 우리가 구성한 로그인 페이지는 login_page 입니다. 그러나 실제로 login_page 페이지가 아니라 JSON입니다. 로그인하지 않고 다른 페이지를 방문 할 때 Spring Security가 자동으로 login_page 페이지로 이동하기 때문입니다. 그러나 Ajax 요청에서 이러한 종류의 점프는 필요하지 않습니다. 내가 원하는 것은 로그인하든 아니든 프롬프트되므로 여기에서 JSON을 반환 할 수 있습니다.
시험
마지막으로, 친구는 우체부 또는 Restclient와 같은 도구를 사용하여 로그인 및 권한 문제를 테스트 할 수 있으므로 시연하지 않습니다.
자, 위의 소개 후, 친구들은 이미 Spring Boot+Spring Security의 Ajax 로그인 요청 처리를 이해했다고 생각합니다. 좋아,이 기사의 전부입니다. 궁금한 점이 있으면 메시지를 남겨 두십시오.