1. 程式人生 > >spring secrity 自定義驗證

spring secrity 自定義驗證

spring secrity 驗證預設是使用username和password。但是我專案的登入是根據使用者的   的工號和密碼進行驗證的,所有 有點不同。


關鍵點是 自己實現了   myAuthenticationProvider;


<?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-3.0.xsd  
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">




<global-method-security pre-post-annotations="enabled" />
<!-- HTTP安全配置 -->
<http auto-config="false" entry-point-ref="authenticationEntryPoint"  access-denied-page="/denied.html">
<intercept-url pattern="/login.html" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/index.html" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/m/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/commons/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/upload/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <intercept-url pattern="/cms/**" access="ROLE_USER"/>
       <!--  <intercept-url pattern="/adminIndex.html" access="ROLE_USER"/> -->
        <intercept-url pattern="/pages/*.html" access="ROLE_USER"/>
       <!--  logout-success-url="/login.html" -->
        <logout logout-url="/j_spring_security_logout" invalidate-session="true" 
            delete-cookies="JSESSIONID" success-handler-ref="myLogoutSuccessHandler"/>
        
        <custom-filter ref="corsFilter" after="PRE_AUTH_FILTER"/>
<custom-filter ref="myLoginFilter" position="FORM_LOGIN_FILTER" />
<custom-filter ref="mySecurityFilter" before="FILTER_SECURITY_INTERCEPTOR" />
</http>

<beans:bean id="corsFilter" class="com.threeti.danfoss.base.filter.SecurityCorsFilter" />

<beans:bean id="sas"
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<beans:property name="maximumSessions" value="1"></beans:property>
<beans:property name="exceptionIfMaximumExceeded"
value="true"></beans:property>
<beans:constructor-arg name="sessionRegistry"
ref="sessionRegistry"></beans:constructor-arg>
</beans:bean>

<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl"></beans:bean>


<beans:bean id="myLoginFilter"
class="com.threeti.danfoss.base.filter.MyUsernamePasswordAuthenticationFilter">

<beans:property name="authenticationManager" ref="myAuthenticationManager"/>  
        <beans:property name="authenticationFailureHandler" ref="failureHandler"/>  
        <beans:property name="authenticationSuccessHandler" ref="successHandler"/>  
<beans:property name="sessionAuthenticationStrategy"
ref="sas"></beans:property>
</beans:bean>



 
    <beans:bean id="successHandler" class="com.threeti.danfoss.base.handler.MyAuthenticationSuccessHandler">  
        <beans:property name="defaultTargetUrl" value="/pages/menu.html#current/wind/surface/level/anim=off/overlay=misery_index/orthographic=39.08,42.42,294/loc=96.475,39.357" />  
    </beans:bean>  
   
    <beans:bean id="failureHandler" class="com.threeti.danfoss.base.handler.MySimpleUrlAuthenticationFailureHandler">  
        <beans:property name="defaultFailureUrl" value="/index.html"/>  
    </beans:bean> 
    
    <beans:bean id="myLogoutSuccessHandler" class="com.threeti.danfoss.base.handler.MyLogoutSuccessHandler">
        <beans:property name="defaultTargetUrl" value="/login.html"/>
        <!-- 下面的 是通過在url引數進行跳轉 -->
        <!-- <property name="targetUrlParameter" value="target-url"/>
      <property name="redirectStrategy" ref="safeRedirectStrategy"/> -->
    </beans:bean> 
    <!-- 安全的RedirectStrategy,主要是判斷跳轉地址是否在白名單中    public class SafeRedirectStrategy implements RedirectStrategy -->
    <!-- <beans:bean id="safeRedirectStrategy" class="com.snsxiu.job.web.security.SafeRedirectStrategy"/> -->
    
<!-- 1.URL過濾器或方法攔截器:用來攔截URL或者方法資源對其進行驗證,其抽象基類為AbstractSecurityInterceptor 
2.資源許可權獲取器:用來取得訪問某個URL或者方法所需要的許可權,介面為SecurityMetadataSource 3.訪問決策器:用來決定使用者是否擁有訪問許可權的關鍵類,其介面為AccessDecisionManager 
呼叫順序為:AbstractSecurityInterceptor呼叫SecurityMetadataSource取得資源的所有可訪問許可權, 然後再呼叫AccessDecisionManager來實現決策,確定使用者是否有許可權訪問該資源。 -->
<!-- 自定義的filter, 必須包含authenticationManager, accessDecisionManager, securityMetadataSource三個屬性 -->
<beans:bean id="mySecurityFilter" class="com.threeti.danfoss.base.security.XaFilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="myAuthenticationManager" />
<beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
<beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
</beans:bean>


<!-- 取HTTP配置中的authenticationManager 設定alias別名 -->
<authentication-manager alias="myAuthenticationManager">
<authentication-provider ref="myAuthenticationProvider"/>
</authentication-manager>




<!-- 使用者詳細資訊管理:資料來源、使用者快取(通過資料庫管理使用者、角色、許可權、資源) -->
<beans:bean id="userDetailsManager" class="com.threeti.danfoss.base.security.XaUserDetailsService">
</beans:bean>

<!-- <beans:bean
class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"
id="passwordEncoder">
</beans:bean> -->

<beans:bean id="myAuthenticationProvider" class="com.threeti.danfoss.base.filter.MyAuthenticationProvider">
<!-- <beans:property name="userDetailsService" ref="userDetailsManager"/> -->
<beans:constructor-arg name="userDetailsService" ref="userDetailsManager"/>
<!-- <beans:property name="passwordEncoder" ref="passwordEncoder"/> -->
</beans:bean>


<!-- 訪問決策器,決定某個使用者具有的角色,是否有足夠的許可權去訪問某個資源。 -->
<beans:bean id="myAccessDecisionManager"
class="com.threeti.danfoss.base.security.XaAccessDecisionManagerService" />




<!-- 資源源資料定義,將所有的資源和許可權對應關係建立起來,即定義某一資源可以被哪些角色去訪問。 -->
<beans:bean id="mySecurityMetadataSource" init-method="loadResourceDefine"
class="com.threeti.danfoss.base.security.XaSecurityMetadataSourceService">
</beans:bean>

<beans:bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login.html" />
</beans:bean>


</beans:beans>



這個是我實現的的  myAuthenticationProvider;


package com.threeti.danfoss.base.filter;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;


import com.threeti.danfoss.base.exception.LoginLockException;
import com.threeti.danfoss.base.repository.XaCmsUserRepository;
import com.threeti.danfoss.base.util.MD5Util;


public class MyAuthenticationProvider implements AuthenticationProvider{
@Autowired
XaCmsUserRepository xaCmsUserRepository;
private UserDetailsService userDetailsService;  
    public MyAuthenticationProvider(UserDetailsService userDetailsService) {  
        this.userDetailsService = userDetailsService;  
    }
    
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}


public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}


@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;  
        String username = token.getName();  
        //從資料庫找到的使用者  
        UserDetails userDetails = null;  
        if(username != null) {  
            userDetails = userDetailsService.loadUserByUsername(username);  
        }  
        //XaCmsUser user =xaCmsUserRepository.findByNumberAndPasswordAndStatus(userDetails.getUsername(),
        //MD5Util.getMD5String(userDetails.getPassword()), XaConstant.UserStatus.status_normal);
        if(userDetails == null) {
        throw new LoginLockException("賬號或者密碼錯誤"); 
        }
        //資料庫使用者的密碼  
        String password = userDetails.getPassword();  
        //與authentication裡面的credentials相比較  
        if(!password.equals(MD5Util.getMD5String((String)token.getCredentials()))) {  
            //throw new BadCredentialsException("Invalid username/password");
            throw new LoginLockException("賬號或者密碼錯誤"); 
        }  
        //授權  
        return new UsernamePasswordAuthenticationToken(userDetails, password,userDetails.getAuthorities());  
}


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

}


我標紅色的部分就是關鍵,在MyAuthenticationProvider  中注入了 UserDetailsService 

,呼叫了loadUserByUsername(username)方法




package com.threeti.danfoss.base.security;


import java.util.ArrayList;
import java.util.List;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;


import com.threeti.danfoss.base.constant.XaConstant;
import com.threeti.danfoss.base.entity.XaCmsUser;
import com.threeti.danfoss.base.exception.LoginLockException;
import com.threeti.danfoss.base.repository.XaCmsUserRepository;
import com.threeti.danfoss.base.util.DateProcessUtil;




/**
 * 登入許可權驗證service
 * @author zj
 *
 */
@Service("MsUserDetailsService")
public class XaUserDetailsService implements UserDetailsService {
    protected static final String ROLE_PREFIX = "ROLE_";
    protected static final GrantedAuthority DEFAULT_USER_ROLE = new SimpleGrantedAuthority(ROLE_PREFIX + "USER");


@Autowired
XaCmsUserRepository xaCmsUserRepository;


public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
XaUserDetails msUserDetails = new XaUserDetails();
try {
XaCmsUser user;
//List<XaCmsUser> userList = xaCmsUserRepository.findByUserName(new String(username.getBytes("ISO-8859-1"),"UTF-8"));

// 這裡也是關鍵,注意,我這裡是通過工號進行查詢的
List<XaCmsUser> userList = xaCmsUserRepository.findByNumber(new String(username.getBytes("ISO-8859-1"),"UTF-8"));
if(userList.size() > 0 && userList.get(0).getStatus() == XaConstant.UserStatus.status_lock){
throw new LoginLockException("您輸入的賬號已被鎖定");
}
/*if(userList.size() > 0 && userList.get(0).getIsAdmin() != 1){
throw new LoginAdminException("您的賬號不是管理員");
}*/
if(userList.size() > 0 && userList.get(0) != null){
user = userList.get(0);
user.setLastLoginDate(DateProcessUtil.getToday(DateProcessUtil.YYYYMMDDHHMMSS));
xaCmsUserRepository.save(user);
msUserDetails.setUsername(user.getNumber());
msUserDetails.setPassword(user.getPassword());
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
GrantedAuthority authority = new SimpleGrantedAuthority(user.getRole().getRoleName());
authorities.add(authority);
//設定使用者oauth通過token訪問的許可權
authorities.add(DEFAULT_USER_ROLE);
authorities.add(new SimpleGrantedAuthority(ROLE_PREFIX + "UNITY"));
authorities.add(new SimpleGrantedAuthority(ROLE_PREFIX + "MOBILE"));
msUserDetails.setAuthorities(authorities);


//msUserDetails.setToken(TokenCenter.issueToken(user.getUserId()));
}
} catch (Exception e) {
e.printStackTrace();
}
return msUserDetails;
}
}