首页 文章

@ModelAttribute不能使用spring安全性

提问于
浏览
2

我正在尝试在登录失败时重定向登录页面上输入的用户名,但在我的控制器中,从“@ModelAttribute(”user“)”检索到的用户的用户名为空 . 当我不使用 spring 安全时,这是有效的 .

我假设表格实际上首先弹出安全性,然后将其重定向到控制器,因此输入的信息在spring security之间丢失 .

如何在不将其发送到链接参数的情况下检索用户?

PS:我试图为“/ loginFailed”创建一个控制器,并在登录失败时将其发送到那里并在该控制器上使用method = RequestMethod.POST .

的LoginController

@RequestMapping(value = "/login", method = RequestMethod.GET)
    public String listPersons(@ModelAttribute("user") User u, @RequestParam(required = false) String authfailed, String logout,
            String denied, Model model) {
        model.addAttribute("user", u);
        String message = "";
        if (authfailed != null) {
            message = "Invalid username or password, try again !";
        } else if (logout != null) {
            message = "Logged Out successfully, login again to continue !";
        } else if (denied != null) {
            message = "Access denied for this user !";
        }
        model.addAttribute("error", message);
        return "login";
    }

login.jsp的

<c:url var="trylogin" value="/j_spring_security_check" ></c:url>
<c:url var="register" value="/register" ></c:url>

<div id="login-box">
    <form:form action="" modelAttribute="user" method="POST">
        <table>
            <tr>
                <td> <form:label path="username"> <spring:message text="Username: "/> </form:label> </td>
                <td> <form:input path="username" /> </td> 
            </tr>
            <tr>
                <td> <form:label path="password"> <spring:message text="Password: "/> </form:label> </td>
                <td> <form:password path="password" /> </td> 
            </tr>
            <tr>
                <td> <input type="submit" value="<spring:message text="Login"/>"
                                    onclick="document.getElementById('user').setAttribute('action', '${trylogin}')"/> </td>
                <td> <input type="submit" value="<spring:message text="Register"/>"
                                    onclick="document.getElementById('user').setAttribute('action', '${register}')"/> </td>
            </tr>
        </table>
    </form:form>
    <c:if test="${not empty error}">
        <div class="error">${error}</div>
    </c:if>
</div>

编辑(解决方案):

谢谢你@James创建一个失败的手是方法,但你的解决方案没有完全正常工作,因为看起来你在failureHandler bean中需要“p:defaultFailureUrl”,即使我有“authentication-failure-url =”/ login?在表单登录中使用authfailed“”

<bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
    p:useForward="true"
    p:defaultFailureUrl="/login"/>

之后我必须使用方法发布为/ login添加另一个函数,因为p:defaultFailureUrl =“/ login?authFailed”将它发送为/ login并且浏览器中的链接保持为“/ j_spring_security_check”我无法理解为什么 .

@RequestMapping(value = "/login", method = RequestMethod.POST)
public String loginFail(@ModelAttribute("user") User u, @RequestParam(required = false) String authfailed, RedirectAttributes redirectAttrs) {
    redirectAttrs.addFlashAttribute("user", u);
    redirectAttrs.addFlashAttribute("error", "Invalid username or password, try again !");
    return "redirect:/login";
}

2 回答

  • 0

    您应该使用AuthenticationFailureHandler . 为了您的目的,它应该足以声明Spring SimpleUrlAuthenticationFailureHandler类的bean,并指定将请求发送到目标URL而不是配置中的默认重定向行为 . 这样您的登录控制器就可以访问原始请求,包括用户名 .

    文件:http://docs.spring.io/autorepo/docs/spring-security/3.2.1.RELEASE/apidocs/org/springframework/security/web/authentication/SimpleUrlAuthenticationFailureHandler.html

    资料来源:https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/authentication/SimpleUrlAuthenticationFailureHandler.java

    <bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
        p:useForward="true"
    />
    

    然后在您的表单登录规范中:

    <security:form-login 
        ...
        authentication-failure-handler-ref="failureHandler"
        ...
    />
    
  • 2

    这是一种错误的方式 . 登录页面控制器仅用于查看此页面 . 对于检查凭证,您需要创建服务,例如:

    @Service("adminDetailsServiceImpl")
    public class AdminDetailsServiceImpl implements UserDetailsService {
        @Autowired
        private SepAdminDao adminDao;
    
        @Override
        public UserDetails loadUserByUsername(String login) {
            SepAdmin admin;
    
            if (StringUtils.isBlank(login))
                throw new UsernameNotFoundException("Admin not found!");
            admin = adminDao.findByEmail(login);
            return new org.springframework.security.core.userdetails.User(
                    admin.getEmail(),
                    admin.getPassword(),
                    getGrantedAuthorities(admin.getRole().getPermissionNames()));
        }
    
        private static List<GrantedAuthority> getGrantedAuthorities(String[] roles) {
            List<GrantedAuthority> authorities = new ArrayList<>();
            for (String role : roles)
                authorities.add(new SimpleGrantedAuthority(role));
            return authorities;
        }
    }
    

    使用spring分配此服务(例如,我为了安全性而查看我的简单配置):

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security.xsd">
        <beans:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
            <beans:property name="hierarchy">
                <beans:value>
                    <!--Admin-->
                    PERM_ROOT > PERM_CREATE_ADMINS
                    PERM_CREATE_ADMINS > PERM_DELETE_ADMINS
                    PERM_DELETE_ADMINS > PERM_EDIT_ADMINS
                    PERM_EDIT_ADMINS > PERM_VIEW_ADMINS
                    <!--Role-->
                    PERM_ROOT > PERM_CREATE_ROLES
                    PERM_CREATE_ROLES > PERM_DELETE_ROLES
                    PERM_DELETE_ROLES > PERM_EDIT_ROLES
                    PERM_EDIT_ROLES > PERM_VIEW_ROLES
                </beans:value>
            </beans:property>
        </beans:bean>
        <beans:bean id="expressionHandler"
                    class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
            <beans:property name="roleHierarchy" ref="roleHierarchy"/>
        </beans:bean>
        <beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
            <beans:property name="decisionVoters">
                <beans:list>
                    <beans:bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
                        <beans:property name="expressionHandler" ref="expressionHandler"/>
                    </beans:bean>
                </beans:list>
            </beans:property>
        </beans:bean>
        <beans:bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
            <beans:constructor-arg ref="roleHierarchy"/>
        </beans:bean>
        <beans:bean id="passwordEncoder"
                    class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
            <beans:constructor-arg value="10"/>
        </beans:bean>
        <http pattern="/resources/js/vendor/language" security="none"/>
        <http pattern="/favicon.ico" security="none"/>
        <http auto-config="true" use-expressions="true" access-denied-page="/403"
              access-decision-manager-ref="accessDecisionManager">
            <intercept-url pattern="/login" access="permitAll"/>
            <!--Admin-->
            <intercept-url pattern="/dashboard" access="hasRole('PERM_ROOT')"/>
            <intercept-url pattern="/admin/create_admin" access="hasRole('PERM_CREATE_ADMINS')"/>
            <intercept-url pattern="/admin/users/*/edit_admin" access="hasRole('PERM_EDIT_ADMINS')"/>
            <intercept-url pattern="/admin/users/*/view_admin" access="hasRole('PERM_VIEW_ADMINS')"/>
            <intercept-url pattern="/admin/users/*/delete_admin" access="hasRole('PERM_DELETE_ADMINS')"/>
            <!--Role-->
            <intercept-url pattern="/role/create_role" access="hasRole('PERM_CREATE_ROLES')"/>
            <intercept-url pattern="/role/*/edit_role" access="hasRole('PERM_EDIT_ROLES')"/>
            <intercept-url pattern="/role/*/view_role" access="hasRole('PERM_VIEW_ROLES')"/>
            <intercept-url pattern="/role/*/delete_role" access="hasRole('PERM_DELETE_ROLES')"/>
            <!--Route-->
            <form-login username-parameter="email"
                        password-parameter="password"
                        login-page="/login" default-target-url="/" authentication-failure-url="/login?failed"/>
            <logout logout-url="/logout" logout-success-url="/login"/>
        </http>
        <authentication-manager alias="authManager">
            <authentication-provider user-service-ref="adminDetailsServiceImpl">
                <password-encoder ref="passwordEncoder"/>
            </authentication-provider>
        </authentication-manager>
    </beans:beans>
    

    然后当用户提交登录表单时,我们会重定向到使用我们服务的/ j_spring_security_check,如果我们有登录异常,我们可以在登录jsp页面检查它:

    <!-- spring_exception -->
    <c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}">
        <p class="alert alert-danger alert-dismissable">
            <spring:message code="Error.Msg.Login"/>
        </p>
        
    </c:if>

    如果成功,我们将重定向到默认目标网址,在我的情况下,重定向到root .

    <form-login username-parameter="email"
             password-parameter="password"
             login-page="/login" default-target-url="/" authentication-failure-url="/login?failed"/>
    

    这就是浏览器链接保持为“/ j_spring_security_check”的原因 .

相关问题