2016-01-17 347 views
0

我想有三个值创建登录页面:春季安全自定义登录

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

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

这是我目前正在使用:

  1. 的Java 8
  2. 春天4.0.3.RELEASE(我用个XML文件)
  3. 春季安全4.0.3.RELEASE
  4. 休眠4.2.21.Final
  5. Thymeleaf 2.1.4.RELEASE

这是我的弹簧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。

有没有人有关于如何做到这一点的例子?或者有没有人有任何建议或指示如何做到这一点?

在此先感谢

+0

“_salt theSource为了比较密码和salt_”。现在怎么办?使用BCrypt?否则,你使用哪种算法? –

回答

0

我已经做了以下变化(因为我现在会用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); 

    } 

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