3

スプリングセキュリティが実装されたスプリングMVC3.0アプリケーションがあります。現在ログインしているユーザーのパスワードを変更するための小さなポップアップを作成しています。フォームを次のアクションに投稿するまでは、すべて順調です。

@RequestMapping(value = "principalchangepassword" , method = RequestMethod.POST)
public @ResponseBody String principalchangepassword(Model uiModel, HttpServletRequest httpServletRequest){
    Principal principal = (Principal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    StandardStringDigester digester = new StandardStringDigester();
    digester.setAlgorithm("SHA-256");   // optionally set the algorithm
    digester.setStringOutputType("hexadecimal");
    digester.setSaltSizeBytes(0);
    digester.setIterations(1);
    String digest = digester.digest(httpServletRequest.getParameter("password1")); 
    principal.setPassword(digest.toLowerCase());
    principal.merge();
    return "Password Updated successfully";
}

現在のプリンシパルのパスワードを更新するためにajax呼び出しを実行すると、次の例外メッセージが表示されます。

org.hibernate.TransientObjectException: object references an unsaved transient instance – save the transient instance before flushing

私は何を間違っているのですか?

4

3 に答える 3

4

BCryptPasswordEncoderを使用してスプリングセキュリティを使用しています。パスワードを変更するために、ユーザーから提供された既存のパスワードをDB値と比較します。

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String existingPassword = ... // Password entered by user
String dbPassword       = ... // Load hashed DB password

if (passwordEncoder.matches(existingPassword, dbPassword)) {
    // Encode new password and store it
} else {
    // Report error 
}
于 2017-04-06T19:09:23.900 に答える
3

わかりました。ステートメントから取得したプリンシパルを使用することにしました。

(Principal) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 

最初にIDを使用して、データベースからプリンシパルを明示的に接続し、変更を加えてからマージする必要がありました。これが完全に機能している最後のアクションです。

@RequestMapping(value = "principalchangepassword" , method = RequestMethod.POST)
public @ResponseBody String principalchangepassword(Model uiModel, HttpServletRequest httpServletRequest){
    Principal principal = (Principal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    Principal me = Principal.findPrincipal(principal.getId());
    me.setPassword(httpServletRequest.getParameter("password1"));
    StandardStringDigester digester = new StandardStringDigester();
    digester.setAlgorithm("SHA-256");   // optionally set the algorithm
    digester.setStringOutputType("hexadecimal");
    digester.setSaltSizeBytes(0);
    digester.setIterations(1);
    String digest = digester.digest(me.getPassword());
    me.setPassword(digest.toLowerCase());
    me.merge();
    return "Password Updated successfully";
}

それが誰かを助けてくれることを願っています。

于 2012-07-17T15:59:31.527 に答える
1

新しいユーザーを作成し、エンコードされたパスワードを設定する方法を探していたので、この質問を見つけました。Binaryrespawnの答えはすでにかなり良いです、私はこの質問に2番目のビューを追加したいと思います。

したがって、パスワードを変更したり、新しいユーザーを作成したりするために、Springと対話する必要はありません。認証されていることを確認する場合(および、アクセス許可を持つ新しいユーザーを作成する場合)を除きます。

最も重要な部分は、PasswordEncoderがSpringで構成されたものと一致し、AuthenticationProviderが保存されたパスワードをユーザーが入力したものと比較するために使用することです。

パスワードを更新する手順は基本的に次のとおりです。

  1. データベースから既存のユーザーをロードします(idまたはusername)。
  2. Springが認証に使用するPasswordEncoderを取得します。
  3. ユーザーを保存します。

新しいユーザーを作成する手順は基本的に次のとおりです。

  1. フロントエンドからユーザーオブジェクトを取得します。
  2. Springが認証に使用するPasswordEncoderを取得します
  3. ユーザーが送信するパスワードをエンコードされたバージョンに置き換えて、ユーザーオブジェクトに戻します。
  4. ユーザーを保存します。

新しいユーザーを作成するためのRESTエンドポイントを定義する例を次に示します。

private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

@POST
@Path("user/create")
@Produces(MediaType.APPLICATION_JSON)
@Secured("ROLE_ADMIN")
public User createUser(User user) {
    if(user.getPassword() == null || user.getPassword().equals("")) {
        //throw exception...
    }
    user.setPassword(passwordEncoder.encode(user.getPassword()));
    userService.save(user);
    return user;
}
于 2014-02-28T11:47:55.613 に答える