Spring MVC的 - 检查使用者是否已经通过Spring Security的登录?(Sprin

2019-06-28 04:59发布

我有一个Spring MVC应用程序。 它使用自己定制的登录页面 。 成功登录后,一个“LOGGED_IN_USER”物体被放置在HttpSession。

我希望只允许通过认证的用户访问的URL。 我知道我可以通过使用网络过滤器实现这一目标。 但是,这部分我想用Spring Security的做(我的支票将保持不变 - 寻找“LOGGED_IN_USER”在HttpSession对象,如果存在的话您登录)。

我的约束是我不能改变目前登录的行为-如果不使用Spring Security呢。

我可以使用哪些方面的Spring Security的独自实现这一目标的一部分-检查是否请求认证(从登录的用户)?

Answer 1:

至少有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>
  • @see 的Spring Security参考,第16.1.1常见的内置表达式
  • @see Spring Security的参考章节16.2 Web安全表达式

每@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表达式讨论:

  • 如何创建春季安全表达式语言注释使用自定义的方法
  • http://bmchild.blogspot.de/2012/02/creating-custom-regex-spring-security.html

但对于拦截<security:intercept-url ... access="myCustomAuthenticatedExpression" />有一个稍微不同的方法可能并不需要处理与私营类的问题。 - 我只是做了它的Spring Security 3.0,但我希望它为3.1了。

1),你需要创建一个从扩展的新类WebSecurityExpressionRoot (前缀网络是重要组成部分!)。

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更新

由于春季安全3.1是有点更容易实现自定义表达式。 一个人并不不再需要sublcass WebSecurityExpressionHandler并覆盖createEvaluationContext 。 代替一个sublass 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;
      }
 }


Answer 2:

另一种解决方案,您可以创建类:

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";
    }
}


Answer 3:

这是你想达到什么样的?

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


Answer 4:

许多认证供应商将创建一个UserDetails对象为主体。

另一种方式,我发现-使用弹簧安全-是检查返回值是否Authentication.getPrincipal()是一个实例UserDetails ; 该方法返回"anonymousUser"String默认情况下)。

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


文章来源: Spring MVC - Checking if User is already logged in via Spring Security?