最近、プロジェクトで問題が発生しました。フロントエンドとバックエンドは分離され、フロントエンドはVUEで行われ、すべてのデータ要求はVUEリソースを使用し、フォームは使用されず、JSONが使用します。 Spring Securityは以前に使用されていたため、ページを処理し、今回はAjaxリクエストを単純に処理したため、遭遇したいくつかの問題を記録しました。ここでの解決策は、AJAX要求に適しているだけでなく、モバイルリクエストの確認も解決します。
プロジェクトを作成します
まず、Spring Bootプロジェクトを作成する必要があります。作成するときは、Web、Spring Security、MySQL、MyBatisを紹介する必要があります(データベースフレームワークは実際には任意です。ここではMyBatisを使用します)。作成後、依存関係ファイルは次のとおりです。
<Dependency> groupId> org.mybatis.spring.boot </groupid> <artifactid> mybatis-spring-boot-starter </artifactid> <バージョン> </version> </dependency> <依存関係> <groupid> org.springframework.boot </groupid> <artifactid> spring-boot-starter-security </artifactid> </dependency> <dependency> groupid> org.springframework.boot </groupid> <artifactid> spring-boot-starter-web </artifactid> </dependency> <依存関係> <グループ</groupid> <artifactid> mysql-connector-java </artifactid> <scope> runtime </scope> </dependency> <dependency> <groupid> commons-codec </groupid> <artifactid> commons-codec </artifactid> <バージョン> 1.11 </バージョン> </despency>
最後のCommons-Codecの依存関係は、私によって手動で追加されたことに注意してください。これは、MD5メッセージダイジェストを生成するために使用できるApacheのオープンソースプロジェクトです。次のテキストでパスワードを処理するだけです。
データベースを作成して構成します
ロジックを簡素化するために、ここで3つのテーブル、つまりユーザーテーブル、ロールテーブル、およびユーザーロールアソシエーションテーブルを次のように作成しました。
次に、application.propertiesでデータベースの簡単な構成を作成する必要があります。ここでは、特定の状況によって決まります。
spring.datasource.url = jdbc:mysql:///vueblogspring.datasource.username = rootspring.datasource.password=123
エンティティクラスを構築します
ここでは、主にユーザークラスの構築を指します。ここのユーザークラスは非常に特別であり、次のようにユーザーデテールインターフェイスを実装する必要があります。
パブリッククラスユーザーはuserdetailsを実装しています{private long id;プライベート文字列ユーザー名;プライベート文字列パスワード。プライベートストリングニックネーム;プライベートブールの有効化。プライベートリスト<ロール>ロール。 @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 <ArniveDauthority> getAuthorities(){list <grantedauthority> authorities = new ArrayList <>(); for(役割:役割){authorities.add(new simpleGrantedAuthority( "role_" + chole.getname()); }当局を返します。 } // getter/setter omit ...} userdetailsインターフェイスを実装した後、このインターフェイスには実装する必要があるいくつかの方法があります。ブール値を返す4つの方法はすべて既知で既知です。有効期間アカウントが有効かどうかを示します。このフィールドは私のデータベースに存在します。したがって、クエリの結果によると、他のものは簡単な期間直接戻ります。 getauthoritiesメソッドは、現在のユーザーの役割情報を返します。ユーザーの役割は、実際には役割のデータです。役割のデータは<grantedauthority> listに変換され、その後返されます。ここに注意すべき点があります。データベースに保存するロール名はすべて「スーパー管理者」、「通常のユーザー」などのようなものであり、 ROLE_のような文字から始めるわけではないため、ここで手動でROLE_を追加する必要があります。
ロールエンティティクラスもあります。これは比較的単純で、データベースのフィールドに従って作成できます。ここでは繰り返しません。
ユーザーサービスを作成します
ここでのユーザーサービスも非常に特別であり、次のようにユーザーDetailsServiceインターフェイスを実装する必要があります。
@servicepublic class userserviceを実装しているuserdetailsservice {@autowired usermapper usermapper; @Autowiredロールマッパーロールマッパー。 @Override public userdetails loaduserbyUsername(s)throws usernamenotfoundexception {user user = usermapper.loduserbyusername(s); if(user == null){// nullを返すことを避けます。ここでは、値が含まれていないユーザーオブジェクトを返します。 } //ユーザーの役割情報を照会し、ユーザーに戻ります。 List <lole> loles = cholesmapper.getRolesbyUid(user.getId()); user.setRoles(役割);ユーザーを返します。 }}userdetailsServiceインターフェイスを実装した後、インターフェイスにLoadUserByUsernameメソッド、つまりユーザー名に基づいてユーザーをクエリする必要があります。ここではMyBatisの2つのマッパーが注入され、UserMapperはユーザーのクエリに使用され、ロールマッパーは役割を照会するために使用されます。 loaduserbyUsernameメソッドでは、最初に渡されたパラメーターに従ってユーザーをクエリします(パラメーターは、ユーザーがログインするときに入力されたユーザー名です)。見つかったユーザーがnullの場合、usernamenotfoundexceptionの例外を直接スローできます。ただし、処理の利便性のために、価値なしにユーザーオブジェクトを返しました。このようにして、その後のパスワード比較プロセス中に、ログインが失敗したことがわかります(ここでは、ビジネスのニーズに応じて調整できます)。見つかったユーザーがnullでない場合、ユーザーIDに基づいてユーザーの役割を照会し、クエリ結果をユーザーオブジェクトに入れます。このクエリの結果は、ユーザーオブジェクトのgetauthoritiesメソッドで使用されます。
セキュリティ構成
最初に私のセキュリティ構成を見てみましょう。次に、1つずつ説明します。
@configurationPublic class websecurityconfig websecurityconfigurerAdapter {@autowired userservice userservice; @Override Protected void Configure(AuthenticationManagerbuilder auth)exception {auth.userdetailsservice(userservice).passwordencoder(new PassiderenCoder(){@Override public String encode(charecence charesecence){return digestutils.md5digestashex(get.tostring(); @Param CharSequence Plantext* @Param S Ciphertext* @return*/ @Overrideパブリックブールマッチ(CharSequence CharSequence、String) } @Override Protected void configure(httpsecurity http)throws exception {http.authorizerequests()antmatchers( "/admin/**")。hasrole( "super admin").anyrequest()。 in.and()。forglogin()。loginpage( "/login_page") httpsertResponse.setContentType(charset = utf-8); .FailureHandler(new AuthenticationFailureHandler(){@Override public void onauthenticationFailure(httpservletrequest、httpservletrequest、httpservletresponse httpservletresponse、httpservletresception e) httpsertresponse.setContentType( "charset = utf-8"); })。loginprocessingurl( "/login").usernameparameter( "username")。passworeparameter( "password")。pimitall()。 } @Override public void configure(websecurity web)throws exception {web.ignoring()。antmatchers( "/reg"); }}これが構成の中核です。聞いてください:
1.まず第一に、これは構成クラスですので、@Configuration Annotationを追加することを忘れないでください。これはSpring Securityの構成であるため、WebSecurityConfigurerAdapterを継承する必要があります。
2。作成されたばかりのユーザーサービスを注入し、後で使用します。
3.Configure(AuthenticationManagerBuilder Auth)メソッドは、認証方法の構成に使用され、auth.userdetailsservice()メソッドのユーザーサービスを渡すために使用されるため、ユーザーサービスのloaduserbyusernameメソッドは、ユーザーがログインするときに自動的に呼び出されます。ログインするときにそれを処理するにはPlantextパスワードも必要であるため、PasswordEncoderを追加し、PasswordEncoderを追加した後、匿名の内部クラスのPasswordEncoderを直接新しいことができます。ここに実装する2つの方法があり、名前を見ることで方法の意味を知ることができます。最初のメソッドエンコードは、明らかに平文を暗号化します。ここでは、MD5メッセージダイジェストを使用します。特定の実装方法は、Commons-Codec依存関係によって提供されます。 2番目のメソッド一致は、パスワードの比較、2つのパラメーター、最初のパラメーターはPlantextパスワード、2番目のパラメーターはciphertextです。ここでは、プレーンテキストを暗号化して暗号文と比較するだけです(これに興味がある場合は、パスワードに塩を追加することを引き続き検討できます)。
4.コンフィグ(httpsecurity http)は、認証ルールなどを構成するために使用されます。認証ルールの構成が有効になることを意味します。Antmatchers( "/admin/ /admin/** ")。私はインターネットで、友人がHasroleメソッドにROLE_を追加するかどうかについて質問があることを見ました。ここに追加しないでください。 HasAuthorityメソッドを使用する場合は、追加する必要があります。 AnyRequest()。Authentipated()は、アクセスする前に他のすべてのパスを認証/ログインする必要があることを意味します。次に、login_pageとしてログインページを構成し、ログイン処理パスは /ログイン、ログインユーザー名はユーザー名、パスワードはパスワードです。これらのパスを直接アクセスするように構成し、ログインログアウトに直接アクセスすることもでき、最後にCSRFを閉じます。 SuccessHandlerでは、応答を使用して、ログインしたJSONを返します。DefaultSuccessurlを使用しないことを忘れないでください。 DefaultSuccessurlは、ログインして正常にログインした後にのみリダイレクトされるページです。同じ理由が故障ハンドラーにも使用されます。
5. Configuration(Websecurity Web)メソッドでいくつかのフィルタリングルールを構成したため、詳細は説明しません。
6.さらに、 /images/** 、 /css/** 、 /js/**などの静的ファイルの場合、デフォルトは傍受されません。
コントローラ
最後に、次のようにコントローラーを見てみましょう。
@RestControllerPublicクラスLoginRegController {/** *このページに自動的にジャンプする場合、ユーザーがログインしていないことを意味し、対応するプロンプトを返すことができます * <p> *この方法でのリクエストのタイプを判断してから、JSONまたはhtml Pablapsに戻るかどうかを決定できます。 respbean loginpage(){return new respbean( "error"、 "まだログインしていない、ログインしてください!"); }}全体として、このコントローラーは比較的簡単です。 Respbeanは簡単なJSONを返しますが、これは詳細ではありません。ここに注意を払う必要があるのは、 login_pageです。構成したログインページはlogin_pageです。しかし、実際、 login_pageページではなく、JSONです。これは、ログインせずに他のページにアクセスすると、Spring Securityが自動的にlogin_pageページにジャンプするためです。ただし、AJAXリクエストでは、この種のジャンプは必要ありません。私が欲しいのは、ログインするかどうかのプロンプトだけなので、ここでJSONを返すことができます。
テスト
最後に、友人はPostmanやRestClientなどのツールを使用してログインと許可の問題をテストできます。そのため、実証することはできません。
OK、上記の紹介の後、友人はすでにSpring Boot+Spring SecurityがAJAXログインリクエストの処理を理解していると信じています。さて、この記事はすべてです。ご質問がある場合は、メッセージを残して話し合ってください。