当前位置: 首页 > 知识库问答 >
问题:

Spring MVC-检查用户是否已通过Spring Security登录?

呼延才俊
2023-03-14

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

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

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

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

共有3个答案

范云
2023-03-14

这就是你想要实现的吗?

<c:choose>
  <c:when test="${pageContext.request.userPrincipal.authenticated}">Show something</c:when>
  <c:otherwise>Show something else</c:otherwise>
</c:choose>
李和裕
2023-03-14

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

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:

之前的解决方案有一个问题,这解释了Peter的评论。

@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";
    }
}
干鑫鹏
2023-03-14

至少有4种不同的方式:

这是最简单的方法

<security:http auto-config="true" use-expressions="true" ...>
   ...
  <security:intercept-url pattern="/forAll/**" access="permitAll" />
  <security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
  • @参见Spring Security Reference,第16.1.1章通用内置表达式
  • @请参阅《Spring Security参考》,第16.2章Web安全表达式

需要<代码>

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

需要<代码>

 @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表达式,例如:

  • 如何创建在spring security表达式语言注释中使用的自定义方法

但对于拦截器<代码>

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并覆盖createEvalue ationContext。取而代之的是一个子AbstractSecurityExpressionHandler

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

 类似资料:
  • 问题内容: 我有一个Spring MVC应用程序。它使用自己的自定义登录页面。成功登录后,在HTTPSession中放置一个“ LOGGED_IN_USER”对象。 我只允许经过身份验证的用户访问URL。我知道我可以通过使用网络过滤器来实现。但是,这部分是我想使用Spring Security要做的(我的检查将保持不变-如果已登录,请在HTTPSession中查找’LOGGED_IN_USER’对

  • 我面临的问题是: 用户首先使用“使用电子邮件注册”进行注册。之后,用户注册了一个谷歌帐户(有相同的电子邮件)。 现在之后,当用户尝试通过电子邮件和密码登录。我得到错误的密码是不正确的,我知道这是因为注册与电子邮件详细信息已经覆盖了谷歌帐户详细信息。 我要显示错误“电子邮件与谷歌帐户链接,请通过谷歌帐户登录”。

  • 问题内容: 我正在开发一个网站,要求用户必须登录才能使用该系统。当前功能为:当用户输入用户名和密码时,将在数据库中进行检查以检查该用户是否存在以及是否输入了正确的密码。然后才允许该用户登录。 到现在为止还不错,现在客户端希望向日志记录功能添加更多功能,即客户端只希望该用户存在一个会话。 IE。如果user1是从PC的一个浏览器登录的,则不应允许他从另一个系统或同一PC的另一个浏览器登录。 我怎么做

  • 如何检查用户是否在公共页面上的Keycloak中进行了身份验证,而不需要用户导航到某个受保护的页面或之前的登录页面?

  • 问题很简单。我想限制来自不同机器/浏览器的相同登录的用户访问:只有一个实时用户会话是可能的。 库用于用户认证和管理。 当然,这可以使用简单的同步化地图等来完成。但问题是:是否为此制定了特殊机制? 这个问题的另一个变体:如何检索使用< code>apache shiro登录系统的所有主题的列表? UPD: 澄清我的问题。我的愿望是有一些这样的代码(我知道,没有这样的类异常,但这个想法必须更干净):