繁体   English   中英

Spring Security自定义登录

[英]Spring security custom login

我试图用三个值创建一个登录页面:

  1. 用户名
  2. 密码
  3. 公司名

我的应用程序支持不同的公司,并且一个用户可能是多个公司的用户,因此,在登录页面中,作为登录的一部分,用户必须选择要登录的公司。

这是我目前正在使用的:

  1. Java 8
  2. Spring 4.0.3.RELEASE(我正在使用xmls文件)
  3. Spring Security 4.0.3。发布
  4. 休眠4.2.21。最终
  5. 胸腺2.1.4。发布

这是我的spring-security.xml

<b:beans xmlns="http://www.springframework.org/schema/security"
         xmlns:b="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-4.1.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security.xsd">


    <b:bean id="passwordEncoder"
            class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
        <b:constructor-arg value="256"/>
        <b:property name="iterations" value="8224"/>
    </b:bean>

    <!-- Define the User property to use for salting password encoding -->
    <b:bean id="saltSource"
            class="org.springframework.security.authentication.dao.ReflectionSaltSource">
        <b:property name="userPropertyToUse" value="userSalt"/>
    </b:bean>

    <b:bean id="userCompanyAuthenticationProvider"
            class="com.mycompany.security.authentication.UserCompanyAuthenticationProvider">

    </b:bean>

    <!--Authentication provider to use for Spring Security-->
    <!--<b:bean id="daoAuthenticationProvider" -->
    <!--class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">-->
    <!--&lt;!&ndash; userDetailsService is annotated at com.mycompany.security.userdetails.UserDetailsServiceImpl &ndash;&gt;-->
    <!--<b:property name="userDetailsService" ref="userDetailsService"/>-->
    <!--<b:property name="passwordEncoder" ref="passwordEncoder"/>-->
    <!--<b:property name="saltSource" ref="saltSource"/>-->
    <!--</b:bean>-->

    <b:bean id="authenticationEntryPoint"
            class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>

    <!--<authentication-manager alias="authenticationManager">-->
    <!--<authentication-provider ref="daoAuthenticationProvider" />-->
    <!--</authentication-manager>-->


    <!-- Turn off Spring Security for the following URL/patterns -->

    <http pattern="/_ui/**" security="none"/>
    <http pattern="/resources/**" security="none"/>

    <!-- Configure the HTTP realm/security settings and enable SpEL expressions -->
    <http use-expressions="true" auto-config="false" entry-point-ref="loginEntryPoint">

        <custom-filter ref="userCompanyFormLoginFilter"
                       position="FORM_LOGIN_FILTER"/>
        <csrf disabled="true"/>
        <!-- Enable remember me cookie functionality -->
        <!--<remember-me key="myappRememberMe"-->
                     <!--token-validity-seconds="2419200"/>-->

        <intercept-url pattern="/favicon.ico" access="permitAll"/>
        <intercept-url pattern="/login" access="permitAll"/>
        <intercept-url pattern="/logout" access="permitAll"/>
        <intercept-url pattern="/auth/**" access="permitAll"/>
        <intercept-url pattern="/signup/**" access="permitAll"/>
        <intercept-url pattern="/static/**" access="permitAll"/>
        <intercept-url pattern="/resources/**" access="permitAll"/>
        <intercept-url pattern="/_ui/**" access="permitAll"/>

        <intercept-url pattern="/user" access="hasRole('ROLE_USER')"/>

        <intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')"/>

        <intercept-url pattern="/**" access="isAuthenticated()"/>

        <access-denied-handler ref="customAccessDeniedHandler"/>

        <!-- Login Page -->
        <!--<form-login login-page="/login" default-target-url="/"-->
        <!--login-processing-url="/static/j_spring_security_check"-->
        <!--authentication-failure-url="/login?error=true" />-->

        <!-- URL for logging out and specific cookies to delete when doing so. -->
        <!--<logout logout-url="/logout" delete-cookies="JSESSIONID"/>-->
        <!-- delete-cookies="JSESSIONID, SPRING_SECURITY_REMEMBER_ME_COOKIE" -->

        <session-management>
            <concurrency-control max-sessions="1"
                                 error-if-maximum-exceeded="false"/>
        </session-management>
    </http>

    <authentication-manager alias="authenticationManager">
        <authentication-provider ref="userCompanyAuthenticationProvider"/>
    </authentication-manager>

    <b:bean id="userCompanyFormLoginFilter" class="com.mycompany.security.filter.UserCompanyAuthenticationFilter">
        <b:property name="filterProcessesUrl" value="/login/form"/>
        <b:property name="authenticationManager" ref="authenticationManager"/>
        <b:property name="usernameParameter" value="username"/>
        <b:property name="passwordParameter" value="password"/>
    </b:bean>

    <b:bean id="loginEntryPoint"
            class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <b:constructor-arg value="/login"/>
    </b:bean>

    <b:bean id="customAccessDeniedHandler" class="com.mycompany.security.AccessDeniedHandlerApp"/>
</b:beans>

这是我的UserCompanyAuthenticationFilter

package com.mycompany.security.filter;
import com.mycompany.security.authentication.UserCompanyAuthenticationToken;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class UserCompanyAuthenticationFilter extends UsernamePasswordAuthenticationFilter
{

    @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException
    {
        if (!request.getMethod().equals("POST"))
        {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String username = obtainUsername(request);
        String password = obtainPassword(request);
        String company = request.getParameter("company");

        UserCompanyAuthenticationToken authRequest = new UserCompanyAuthenticationToken(username, password, company);

        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }

}

这是我的UserCompanyAuthenticationProvider:

package com.mycompany.security.authentication;
import com.mycompany.entity.User;
import com.mycompany.myapp.dao.service.CompanyService;
import com.mycompany.myapp.dao.service.LoginService;
import com.mycompany.security.RoleEnumerator;
import com.mycompany.security.UnknownRoleException;
import org.apache.log4j.Logger;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;

public class UserCompanyAuthenticationProvider implements AuthenticationProvider
{

    private LoginService loginService;

    private CompanyService companyService;

    private static final Logger LOGGER = Logger.getLogger(UserCompanyAuthenticationProvider.class);

    @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException
    {
        UserCompanyAuthenticationToken token = (UserCompanyAuthenticationToken) authentication;
        String username = token.getName();
        String company = token.getCompany();

        User user = null;
        if (username != null)
        {
            user = loginService.getByUsername(username, companyService.get(Long.parseLong(company)));
        }

        if (user == null)
        {
            throw new BadCredentialsException("Invalid username - password");
        }

        String password = user.getPasswordHash();

        if (!loginService.isValidUsernameAndPasswordHashCombination(username, password))
        {
            throw new BadCredentialsException("Invalid username - password");
        }

        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        try
        {
            RoleEnumerator.getApplicableRoles(user)
                    .forEach(role -> authorities.add(new SimpleGrantedAuthority(role.toString())));

        }
        catch (UnknownRoleException rex)
        {
            LOGGER.error(rex.getMessage(), rex);
        }

        return new UserCompanyAuthenticationToken(user.getUsername(), password, authorities, company);

    }

    @Override public boolean supports(Class<?> authentication)
    {
        return UserCompanyAuthenticationToken.class.equals(authentication);
    }

    @Inject public void setLoginService(LoginService loginService)
    {
        this.loginService = loginService;
    }

    @Inject public void setCompanyService(CompanyService companyService)
    {
        this.companyService = companyService;
    }

}

这是我的UserCompanyAuthenticationToken

package com.mycompany.security.authentication;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;

public class UserCompanyAuthenticationToken extends UsernamePasswordAuthenticationToken
{
    private final String company;

    public UserCompanyAuthenticationToken(String principal, String credentials, String company)
    {
        super(principal, credentials);
        this.company = company;
    }

    public UserCompanyAuthenticationToken(String principal, String credentials,
            Collection<? extends GrantedAuthority> authorities, String company)
    {
        super(principal, credentials, authorities);
        this.company = company;
    }

    public String getCompany()
    {
        return company;
    }
}

到目前为止,我已经在httprequest中发送了三个值(用户名,密码和公司),并且一切正常。

但是,密码未编码,我想做的是对密码进行编码并发送saltSource以便比较密码和salt。

有人有一个关于如何执行此操作的示例吗?或者有人对如何执行此操作有任何建议或指示吗?

提前致谢

我进行了以下更改(目前,因为我将使用BCryptPasswordEncoder作为推荐的@szymon)

这是我的security.xml:

 <b:bean id="passwordEncoder"
            class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
        <b:constructor-arg value="256"/>
        <b:property name="iterations" value="8224"/>
    </b:bean>

   <b:bean id="userCompanyAuthenticationProvider"
            class="com.digitalkresko.security.authentication.UserCompanyAuthenticationProvider">
        <b:property name="passwordEncoder" ref="passwordEncoder"/>
    </b:bean>

然后,我在UserCompanyAuthenticationProvider中进行了以下更改:

public class UserCompanyAuthenticationProvider implements AuthenticationProvider
{

    private LoginService loginService;

    private CompanyService companyService;

    **private ShaPasswordEncoder passwordEncoder;**

    private static final Logger LOGGER = Logger.getLogger(UserCompanyAuthenticationProvider.class);

    @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException
    {
        UserCompanyAuthenticationToken token = (UserCompanyAuthenticationToken) authentication;
        String username = token.getName();
        String company = token.getCompany();

        User user = null;
        if (username != null)
        {
            user = loginService.getByUsername(username, companyService.get(Long.parseLong(company)));
        }

        if (user == null)
        {
            throw new BadCredentialsException("Invalid username - password");
        }

        String password = passwordEncoder.encodePassword(token.getCredentials().toString(), user.getUserSalt());

        if (!loginService.isValidUsernameAndPasswordHashCombination(username, password))
        {
            throw new BadCredentialsException("Invalid username - password");
        }

        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        try
        {
            RoleEnumerator.getApplicableRoles(user)
                    .forEach(role -> authorities.add(new SimpleGrantedAuthority(role.toString())));

        }
        catch (UnknownRoleException rex)
        {
            LOGGER.error(rex.getMessage(), rex);
        }

        return new UserCompanyAuthenticationToken(user.getUsername(), password, authorities, company);

    }

但是,我不确定这是否是验证用户名/密码的正确方法。 你怎么看?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM