18

これが私の春のセキュリティ設定です:

<http pattern="/auth/login" security="none" />
<http pattern="/auth/loginFailed" security="none" />
<http pattern="/resources/**" security="none" />

<http auto-config="true" access-decision-manager-ref="accessDecisionManager">
    <intercept-url pattern="/auth/logout" access="permitAll"/>
    <intercept-url pattern="/admin/**" access="ADMINISTRATIVE_ACCESS"/>
    <intercept-url pattern="/**" access="XYZ_ACCESS"/>

    <form-login
        login-page="/auth/login"
        authentication-failure-url="/auth/loginFailed"
        authentication-success-handler-ref="authenticationSuccessHandler" />
    <logout logout-url="/auth/logout" logout-success-url="/auth/login" />
</http>

これにより、ユーザーが最初に要求したページにauthenticationSuccessHandlerリダイレクトSavedRequestAwareAuthenticationSuccessHandlerされることが保証されます。

ただし、/auth/loginは とマークされているsecurity="none"ため、ユーザーがログイン後にログイン ページにアクセスすると、ユーザーをホームページに正常にリダイレクトできません。これも適切なユーザー エクスペリエンスだと思います。

以下も試しましたが、おそらく属性が原因で、Principalオブジェクトは常にです。nullsecurity="none"

@RequestMapping(value = "/auth/login", method = GET)
public String showLoginForm(HttpServletRequest request, Principal principal) {
    if(principal != null) {
        return "redirect:/";
    }

    return "login";
}
4

6 に答える 6

9

前回よりも深くトピックを確認したところ、コントローラーでユーザーが自分で認証されているかどうかを判断する必要があることがわかりました。Row Winch (Spring Security dev)は次のように述べています

Spring Security は、アプリケーションの内部を認識しません (つまり、ユーザーがログインしているかどうかに基づいてログイン ページを変更する場合)。ログイン ページが要求され、ユーザーがログインしているときにホームページを表示するにSecurityContextHolderは、ログイン ページ (またはそのコントローラー) で を使用し、ユーザーをホームページにリダイレクトまたは転送します。

したがって、解決策は、ユーザーのリクエスト/auth/loginが匿名かどうかを判断することです。以下のようになります。

applicationContext-security.xml :

<http auto-config="true" use-expressions="true"
        access-decision-manager-ref="accessDecisionManager">
    <intercept-url pattern="/auth/login" access="permitAll" />
    <intercept-url pattern="/auth/logout" access="permitAll" />
    <intercept-url pattern="/admin/**" access="ADMINISTRATIVE_ACCESS" />
    <intercept-url pattern="/**" access="XYZ_ACCESS" />

    <form-login login-page="/auth/login"
        authentication-failure-url="/auth/loginFailed"
        authentication-success-handler-ref="authenticationSuccessHandler" />
    <logout logout-url="/auth/logout" logout-success-url="/auth/login" />
</http>

<beans:bean id="defaultTargetUrl" class="java.lang.String">
    <beans:constructor-arg value="/content" />
</beans:bean>

<beans:bean id="authenticationTrustResolver"
        class="org.springframework.security.authentication.AuthenticationTrustResolverImpl" />

<beans:bean id="authenticationSuccessHandler"
        class="com.example.spring.security.MyAuthenticationSuccessHandler">
    <beans:property name="defaultTargetUrl" ref="defaultTargetUrl" />
</beans:bean>

applicationContext.xml Bean 定義に追加します。

<bean id="securityContextAccessor"
    class="com.example.spring.security.SecurityContextAccessorImpl" />

クラスです

public final class SecurityContextAccessorImpl
      implements SecurityContextAccessor {

  @Autowired
  private AuthenticationTrustResolver authenticationTrustResolver;

  @Override
  public boolean isCurrentAuthenticationAnonymous() {
    final Authentication authentication =
        SecurityContextHolder.getContext().getAuthentication();
    return authenticationTrustResolver.isAnonymous(authentication);
  }
}

シンプルなインターフェースの実装

public interface SecurityContextAccessor {
  boolean isCurrentAuthenticationAnonymous();
}

SecurityContextHolderコードへのアクセスはコントローラーから切り離されています。この回答からの提案に従いました。したがって、SecurityContextAccessorインターフェイスです。)

最後になりましたが、コントローラのリダイレクト ロジック:

@Controller
@RequestMapping("/auth")
public class AuthController {
  @Autowired
  SecurityContextAccessor securityContextAccessor;

  @Autowired
  @Qualifier("defaultTargetUrl")
  private String defaultTargetUrl;

  @RequestMapping(value = "/login", method = RequestMethod.GET)
  public String login() {
    if (securityContextAccessor.isCurrentAuthenticationAnonymous()) {
      return "login";
    } else {
      return "redirect:" + defaultTargetUrl;
    }
  }
}

String Bean の定義defaultTargetUrlはハックのように思えますが、URL をハードコーディングしないためのより良い方法はありません... (実際、私たちのプロジェクトでは、<util:constant>静的な final String フィールドを含むクラスで使用しています)。

于 2012-09-26T13:04:12.150 に答える
7

ログインページを次のように制限しROLE_ANONYMOUSて設定することもでき<access-denied-handler />ます。

<access-denied-handler ref="accessDeniedHandler" />
<intercept-url pattern="/auth/login" access="ROLE_ANONYMOUS" />

ハンドラーで、ユーザーが既に認証されているかどうかを確認します。

@Service
public class AccessDeniedHandler extends AccessDeniedHandlerImpl {
    private final String HOME_PAGE = "/index.html";

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && !(auth instanceof AnonymousAuthenticationToken)) {
            response.sendRedirect(HOME_PAGE);
        }

        super.handle(request, response, e);
    }
}
于 2015-01-13T14:33:28.190 に答える
4

この目的のために Redirect Interceptor を実装します。

インターセプター (実装HandlerInterceptorインターフェース) は、誰かがログイン ページにアクセスしようとしたかどうかをチェックし、このユーザーが既にログインしている場合、インターセプターはインデックス ページにリダイレクトを送信します。

public class LoginPageRedirectInterceptor extends HandlerInterceptorAdapter {    

    private String[] loginPagePrefixes = new String[] { "/login" };

    private String redirectUrl = "/index.html";

    private UrlPathHelper urlPathHelper = new UrlPathHelper();

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {

        if (isInLoginPaths(this.urlPathHelper.getLookupPathForRequest(request))
                           && isAuthenticated()) {
            response.setContentType("text/plain");
            sendRedirect(request, response);
            return false;
        } else {
            return true;
        }
    }

    private boolean isAuthenticated() {
        Authentication authentication =
                        SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            return false;
        }
        if (authentication instanceof AnonymousAuthenticationToken) {
            return false;
        }
        return authentication.isAuthenticated();
    }

    private void sendRedirect(HttpServletRequest request,
                              HttpServletResponse response) {

        String encodedRedirectURL = response.encodeRedirectURL(
                                 request.getContextPath() + this.redirectUrl);
        response.setStatus(HttpStatus.SC_TEMPORARY_REDIRECT);
        response.setHeader("Location", encodedRedirectURL);
    }

    private boolean isInLoginPaths(final String requestUrl) {   
        for (String login : this.loginPagePrefixes) {
            if (requestUrl.startsWith(login)) {
                return true;
            }
        }
        return false;
    }
}
于 2013-08-02T08:21:12.270 に答える
0
<http pattern="/login" auto-config="true" disable-url-rewriting="true">
  <intercept-url pattern="/login" access="ROLE_ANONYMOUS"/>
  <access-denied-handler error-page="/index.jsp"/>
</http>
于 2016-03-07T20:04:11.837 に答える
0

要素access-denied-pageの属性によって、またはdtrunkが拒否されたアクセスのハンドラーを書き込むように、単純なフローを維持できます。構成は次のようになりますhttp

<http access-denied-page="/403" ... >
 <intercept-url pattern="/login" access="ROLE_ANONYMOUS" />
 <intercept-url pattern="/user/**" access="ROLE_USER" />
 <intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
 <form-login login-page="/login" default-target-url="/home" ... />
 ...
</http>

のコントローラーで/403

@RequestMapping(value = "/403", method = RequestMethod.GET)
public String accessDenied() { //simple impl
    return "redirect:/home";
}

そして/home

@RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Authentication authentication) {
 // map as many home urls with Role
    Map<String, String> dashBoardUrls = new HashMap<String, String>();
    dashBoardUrls.put("ROLE_USER", "/user/dashboard");
    dashBoardUrls.put("ROLE_ADMIN", "/admin/dashboard");

    String url = null;

    Collection<? extends GrantedAuthority> grants = authentication
            .getAuthorities();
 // for one role per user
    for (GrantedAuthority grantedAuthority : grants) {
        url = dashBoardUrls.get(grantedAuthority.getAuthority());
    }
    if (url == null)
        return "/errors/default_access_denied.jsp";

    return "redirect:" + url;
}

ログインせずにリクエストを行うと、セキュリティによって自動的/admin/dashboardにリダイレクトされます/login

于 2016-02-04T06:45:38.070 に答える