web-dev-qa-db-ja.com

Spring MVC-ユーザーが既にSpring Security経由でログインしているかどうかを確認しますか?

Spring MVCアプリケーションがあります。独自のカスタムログインページを使用。ログインに成功すると、「LOGGED_IN_USER」オブジェクトがHTTPSessionに配置されます。

認証されたユーザーのみがURLにアクセスできるようにします。 Webフィルターを使用してこれを達成できることを知っています。しかし、この部分はSpring Securityを使用してやりたいです(私のチェックは同じままです-ログインしている場合は、HTTPSessionで 'LOGGED_IN_USER'オブジェクトを探します)。

私の制約は、現在ログイン動作を変更できないことです-それはまだSpring Securityを使用しません。

Spring Securityのどの側面を使用してこの部分だけを達成できますか-リクエストが(ログインしたユーザーから)認証されているかどうかを確認しますか?

40
Jasper

少なくとも4つの異なる方法があります。

スプリングセキュリティXML設定

これが最も簡単な方法です

_<security:http auto-config="true" use-expressions="true" ...>
   ...
  <security:intercept-url pattern="/forAll/**" access="permitAll" />
  <security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
_

@Securedアノテーションごと

_<global-method-security secured-annotations="enabled" />_が必要です

_@Secured("ROLE_ADMIN")
@RequestMapping(params = "onlyForAdmins")    
public ModelAndView onlyForAdmins() {
    ....
}
_

@PreAuthorizeアノテーションごと

_<global-method-security pre-post-annotations="enabled" />_が必要です

_ @PreAuthorize("isAuthenticated()")
 @RequestMapping(params = "onlyForAuthenticated")
 public ModelAndView onlyForAuthenticatedUsers() {
     ....
 }
_

プログラマティック

_ SecurityContextHolder.getContext().getAuthentication() != null &&
 SecurityContextHolder.getContext().getAuthentication().isAuthenticated() &&
 //when Anonymous Authentication is enabled
 !(SecurityContextHolder.getContext().getAuthentication() 
          instanceof AnonymousAuthenticationToken) 
_

カスタム式

組み込み式が十分でない場合は、それらを拡張できます。メソッド注釈用のSpEL式を拡張する方法については、ここで例を挙げて説明します。

しかし、インターセプター_<security:intercept-url ... access="myCustomAuthenticatedExpression" />_には、わずかに異なるアプローチがあり、プライベートクラスの問題に対処する必要はありません。 -Spring Security 3.0でのみ実行しましたが、3.1でも動作することを願っています。

1.)WebSecurityExpressionRootから拡張する新しいクラスを作成する必要があります(プレフィックスWebは重要な部分です!)。

_public class MyCustomWebSecurityExpressionRoot
         extends WebSecurityExpressionRoot {
     public MyCustomWebSecurityExpressionRoot(Authentication a,
                 FilterInvocation f) {
          super(a, f);
     }

     /** That method is the one that does the expression evaluation! */
     public boolean myCustomAuthenticatedExpression() {
        return super.request.getSession().getValue("myFlag") != null;
     }
}
_

2.)DefaultWebSecurityExpressionRootHandlerを拡張して、カスタム式のルートを提供するハンドラーが必要です

_ public class MyCustomWebSecurityExpressionHandler
              extends DefaultWebSecurityExpressionHandler {

      @Override        
      public EvaluationContext createEvaluationContext(Authentication a,
                FilterInvocation f) {
          StandardEvaluationContext ctx =
                   (StandardEvaluationContext) super.createEvaluationContext(a, f);

           WebSecurityExpressionRoot myRoot =
                    new MyCustomWebSecurityExpressionRoot(a, f);

           ctx.setRootObject(myRoot);
           return ctx;
      }
 }
_

3.)次に、ハンドラーを投票者に登録する必要があります

_<security:http use-expressions="true"
 access-decision-manager-ref="httpAccessDecisionManager" ...>
      ...
    <security:intercept-url pattern="/restricted/**"
              access="myCustomAuthenticatedExpression" />         
      ...
</security:http>

<bean id="httpAccessDecisionManager"
      class="org.springframework.security.access.vote.AffirmativeBased">
    <constructor-arg name="decisionVoters">
            <list>
                <ref bean="webExpressionVoter" />
            </list>
    </constructor-arg>
</bean>

<bean id="webExpressionVoter"
      class="org.springframework.security.web.access.expression.WebExpressionVoter">
    <property name="expressionHandler"
              ref="myCustomWebSecurityExpressionHandler" />
</bean>

<bean id="myCustomWebSecurityExpressionHandler"
    class="MyCustomWebSecurityExpressionHandler" />
_

Spring Security 3.1アップデート

Spring Security 3.1以降、カスタム式を実装するのが少し簡単になりました。 WebSecurityExpressionHandlerをサブクラス化し、createEvaluationContextをオーバーライドする必要はなくなりました。代わりに、1つのサブクラス_AbstractSecurityExpressionHandler<FilterInvocation>_またはそのサブクラスDefaultWebSecurityExpressionHandlerをオーバーライドし、SecurityExpressionOperations createSecurityExpressionRoot(final Authentication a, final FilterInvocation f)をオーバーライドします。

_ public class MyCustomWebSecurityExpressionHandler
              extends DefaultWebSecurityExpressionHandler {

      @Override        
      public SecurityExpressionOperations createSecurityExpressionRoot(
                Authentication a,
                FilterInvocation f) {
           WebSecurityExpressionRoot myRoot =
                    new MyCustomWebSecurityExpressionRoot(a, f);

           myRoot.setPermissionEvaluator(getPermissionEvaluator());
           myRoot.setTrustResolver(this.trustResolver);
           myRoot.setRoleHierarchy(getRoleHierarchy());
           return myRoot;
      }
 }
_
108
Ralph

別の解決策として、クラスを作成できます:

public class AuthenticationSystem {
    public static boolean isLogged() {
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return null != authentication && !("anonymousUser").equals(authentication.getName());
    }
    // ...
    // Any another methods, for example, logout
}

次に、コントローラーで:

@Controller
@RequestMapping(value = "/promotion")
public final class PromotionController {  
    @RequestMapping(value = {"", "/"}, method = RequestMethod.GET)
    public final String root() {
        if (!AuthenticationSystem.isLogged()) return "login"; // or some logic
        // some logic
        return "promotion/index";
    }
}

[〜#〜] ps [〜#〜]

以前のソリューションには問題があり、コメントでピーターを説明しています。

@Controller
@RequestMapping(value = "/promotion")
public final class PromotionController {  
    @RequestMapping(value = {"", "/"}, method = RequestMethod.GET)
    public final String root(final Principal principal) {
        if (null == principal) return "login"; // or some logic
        // some logic
        return "promotion/index";
    }
}
14

これはあなたが達成しようとしていることですか?

<c:choose>
  <c:when test="${pageContext.request.userPrincipal.authenticated}">Show something</c:when>
  <c:otherwise>Show something else</c:otherwise>
</c:choose>
9

認証プロバイダーの多くは、プリンシパルとしてUserDetailsオブジェクトを作成します。

私が見つけた別の方法-spring-securityを使用する-は、Authentication.getPrincipal()の戻り値がUserDetailsのインスタンスであるかどうかをチェックすることです。このメソッドは、デフォルトで"anonymousUser"String)を返します。

boolean isUserLoggedIn(){
   return SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails
}
0
peter