Spring MVCアプリケーションがあります。独自のカスタムログインページを使用。ログインに成功すると、「LOGGED_IN_USER」オブジェクトがHTTPSessionに配置されます。
認証されたユーザーのみがURLにアクセスできるようにします。 Webフィルターを使用してこれを達成できることを知っています。しかし、この部分はSpring Securityを使用してやりたいです(私のチェックは同じままです-ログインしている場合は、HTTPSessionで 'LOGGED_IN_USER'オブジェクトを探します)。
私の制約は、現在ログイン動作を変更できないことです-それはまだSpring Securityを使用しません。
Spring Securityのどの側面を使用してこの部分だけを達成できますか-リクエストが(ログインしたユーザーから)認証されているかどうかを確認しますか?
少なくとも4つの異なる方法があります。
これが最も簡単な方法です
_<security:http auto-config="true" use-expressions="true" ...>
...
<security:intercept-url pattern="/forAll/**" access="permitAll" />
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
_
_<global-method-security secured-annotations="enabled" />
_が必要です
_@Secured("ROLE_ADMIN")
@RequestMapping(params = "onlyForAdmins")
public ModelAndView onlyForAdmins() {
....
}
_
_<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;
}
}
_
別の解決策として、クラスを作成できます:
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";
}
}
これはあなたが達成しようとしていることですか?
<c:choose>
<c:when test="${pageContext.request.userPrincipal.authenticated}">Show something</c:when>
<c:otherwise>Show something else</c:otherwise>
</c:choose>
認証プロバイダーの多くは、プリンシパルとしてUserDetailsオブジェクトを作成します。
私が見つけた別の方法-spring-securityを使用する-は、Authentication.getPrincipal()
の戻り値がUserDetails
のインスタンスであるかどうかをチェックすることです。このメソッドは、デフォルトで"anonymousUser"
(String
)を返します。
boolean isUserLoggedIn(){
return SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails
}