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"
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- 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="/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;
}
}