J'ai une application Spring MVC. Il utilise sa propre page de connexion personnalisée . Une fois la connexion réussie, un objet 'LOGGED_IN_USER' est placé dans HTTPSession.
Je souhaite autoriser uniquement les utilisateurs authentifiés à accéder aux URL. Je sais que je peux y parvenir en utilisant un filtre Web. Mais, cette partie que je veux faire avec Spring Security (mon chèque restera le même - cherchez l’objet 'LOGGED_IN_USER' dans HTTPSession, si vous êtes présent, vous êtes connecté).
Ma contrainte est que je ne peux pas changer le comportement de connexion à l'heure actuelle - cela n'utilisera pas encore Spring Security.
Quel aspect de Spring Security puis-je utiliser pour réaliser cette partie seul - vérifier si la demande est authentifiée (par l'utilisateur connecté)?
Il y a au moins 4 manières différentes:
c'est le moyen le plus simple
<security:http auto-config="true" use-expressions="true" ...>
...
<security:intercept-url pattern="/forAll/**" access="permitAll" />
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
nécessite <global-method-security secured-annotations="enabled" />
@Secured("ROLE_ADMIN")
@RequestMapping(params = "onlyForAdmins")
public ModelAndView onlyForAdmins() {
....
}
nécessite <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)
Si les expressions intégrées ne suffisent pas, vous pouvez les développer. Comment étendre les expressions SpEL pour les annotations de méthode est discuté par exemple ici:
Mais pour l'intercepteur <security:intercept-url ... access="myCustomAuthenticatedExpression" />
, une approche légèrement différente est possible, il n'est pas nécessaire de traiter le problème de la classe privée. - Je ne l'ai fait que pour Spring Security 3.0, mais j'espère que cela fonctionnera aussi pour 3.1.}
1.) vous devez créer une nouvelle classe qui s'étend de WebSecurityExpressionRoot
(le préfixe Web est la partie importante!).
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.) vous avez besoin d’une extension de la DefaultWebSecurityExpressionRootHandler
pour disposer d’un gestionnaire fournissant votre expression personnalisée root
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.) Ensuite, vous devez enregistrer votre gestionnaire auprès des électeurs
<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 Update
Depuis Spring Security 3.1, il est un peu plus facile d'implémenter une expression personnalisée. Il n'est plus nécessaire de sous-classer WebSecurityExpressionHandler
et de remplacer createEvaluationContext
. Au lieu de cela, une sous-classe AbstractSecurityExpressionHandler<FilterInvocation>
ou sa sous-classe DefaultWebSecurityExpressionHandler
et outrepasse 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;
}
}
Une autre solution, vous pouvez créer une classe:
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
}
Ensuite, dans le contrôleur:
@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:
La solution précédente a un problème, ce qui explique Peter dans les commentaires.
@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";
}
}
Est-ce ce que vous essayez d'atteindre?
<c:choose>
<c:when test="${pageContext.request.userPrincipal.authenticated}">Show something</c:when>
<c:otherwise>Show something else</c:otherwise>
</c:choose>
La plupart des fournisseurs d'authentification créeront un objet UserDetails en tant que principal.
Une autre méthode que j'ai trouvée - en utilisant Spring-security - consiste à vérifier si la valeur de retour de Authentication.getPrincipal()
est une instance de UserDetails
; la méthode retourne "anonymousUser"
(String
) par défaut.
boolean isUserLoggedIn(){
return SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails
}