복붙노트

[SPRING] Spring MVC - 사용자가 이미 Spring Security를 ​​통해 로그인했는지 확인하고 있습니까?

SPRING

Spring MVC - 사용자가 이미 Spring Security를 ​​통해 로그인했는지 확인하고 있습니까?

나는 Spring MVC 애플리케이션을 가지고있다. 그것은 자신의 커스텀 로그인 페이지를 사용한다. 로그인에 성공하면 'LOGGED_IN_USER'객체가 HTTPSession에 배치됩니다.

인증 된 사용자 만 URL에 액세스하도록 허용하려고합니다. 웹 필터를 사용하여이 작업을 수행 할 수 있음을 알고 있습니다. 하지만,이 부분은 Spring Security를 ​​사용하고 싶습니다. (제 체크는 동일하게 유지됩니다 - 현재 로그인되어있는 경우 HTTPSession에서 'LOGGED_IN_USER'객체를 찾으십시오).

제약 조건으로 현재 로그인 동작을 변경할 수 없습니다. 아직 스프링 보안을 사용하지 않을 것입니다.

이 부분 만 단독으로 구현하기 위해 Spring Security의 어떤 측면을 사용할 수 있습니까? (로그인 한 사용자의) 요청이 인증되었는지 확인하십시오.

해결법

  1. ==============================

    1.적어도 4 가지 방법이 있습니다.

    적어도 4 가지 방법이 있습니다.

    이것이 가장 쉬운 방법이다.

    <security:http auto-config="true" use-expressions="true" ...>
       ...
      <security:intercept-url pattern="/forAll/**" access="permitAll" />
      <security:intercept-url pattern="/**" access="isAuthenticated()" />
    </security:http>
    

    가 필요합니다.

    @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 3.0에 대해서만 해봤지만, 3.1에서도 작동하기를 바란다.

    1.) WebSecurityExpressionRoot (Prefix 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" />
    

    스프링 보안 3.1 업데이트

    Spring Security 3.1 이후 사용자 정의 표현을 구현하는 것이 약간 더 쉽습니다. 하나는 더 이상 WebSecurityExpressionHandler를 서브 클래 싱하지 않고 createEvaluationContext를 대체 할 필요가 없습니다. 대신 AbstractSecurityExpressionHandler 또는 그 서브 클래스 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;
          }
     }
    
  2. ==============================

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

    추신:

    이전 솔루션에는 문제가있어 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";
        }
    }
    
  3. ==============================

    3.이게 당신이 성취하려고하는 것입니까?

    이게 당신이 성취하려고하는 것입니까?

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

    4.Spring 보안을 사용하여 발견 한 또 다른 방법은 Authentication.getPrincipal ()의 반환 값이 UserDetails의 인스턴스인지 여부를 확인하는 것입니다. 이 메서드는 기본적으로 "anonymousUser"(String)을 반환합니다.

    Spring 보안을 사용하여 발견 한 또 다른 방법은 Authentication.getPrincipal ()의 반환 값이 UserDetails의 인스턴스인지 여부를 확인하는 것입니다. 이 메서드는 기본적으로 "anonymousUser"(String)을 반환합니다.

    boolean isUserLoggedIn(){
       return SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails
    }
    
  5. from https://stackoverflow.com/questions/12371770/spring-mvc-checking-if-user-is-already-logged-in-via-spring-security by cc-by-sa and MIT license