47

我有一个 Spring MVC 应用程序。它使用自己的自定义登录页面。成功登录后,会在 HTTPSession 中放置一个“LOGGED_IN_USER”对象。

我想只允许经过身份验证的用户访问 URL。我知道我可以通过使用网络过滤器来实现这一点。但是,这部分我想使用 Spring Security 来完成(我的检查将保持不变 - 在 HTTPSession 中查找“LOGGED_IN_USER”对象,如果您已登录)。

我的限制是我目前无法更改登录行为 - 还不会使用 Spring Security。

我可以使用 Spring Security 的哪个方面来单独实现这部分 - 检查请求是否经过身份验证(来自登录用户)?

4

6 回答 6

125

至少有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 开始,实现自定义表达式要容易一些。不再需要 sublcasWebSecurityExpressionHandler和 override createEvaluationContext。而是一个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;
      }
 }
于 2012-09-11T14:54:04.230 回答
18

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

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";
    }
}
于 2015-08-13T22:21:33.663 回答
9

这是你想要达到的目标吗?

<c:choose>
  <c:when test="${pageContext.request.userPrincipal.authenticated}">Show something</c:when>
  <c:otherwise>Show something else</c:otherwise>
</c:choose>
于 2013-02-05T03:35:46.320 回答
2

许多身份验证提供程序将创建一个 UserDetails 对象作为主体。

我发现的另一种方法 - 使用 spring-security - 是检查返回值是否Authentication.getPrincipal()UserDetails; 该方法默认返回"anonymousUser"( String)。

boolean isUserLoggedIn(){
   return SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails
}
于 2018-12-31T10:47:38.123 回答
0

您可以简单地创建一个扩展WebSecurityConfigurerAdapter的类并在匹配的 URL中 添加经过身份验证的

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/User/**").authenticated()
 }

你已准备好出发

于 2020-12-27T14:10:34.373 回答
0

我做了一个看起来像这样的端点:

    @GetMapping("/api/authorize")
    public boolean isUserLoggedIn() {
        boolean isLoggedIn = false;
        try {
            SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            isLoggedIn = true;
        } catch (Exception e) {
            isLoggedIn = false;
        }
        return isLoggedIn;
    }
于 2022-02-14T19:17:17.640 回答