Spring security實現國際化問題
阿新 • • 發佈:2018-09-07
ryu rep util ets prope name format 自帶 method
這兩天Spring用戶登錄國際化這個問題困擾我好久啊,於昨天晚上終於把它幹掉了。
場景就是我們公司的產品-incopat,需要支持中英文,用戶登錄這塊用的spring自帶的security,需求講的通俗一點就是,中文版提示中文提示信息,英文版提示英文版信息,廢話不多說,見代碼。
首先配置文件
security-config.xml
1 <beans:bean id="customUsernamePasswordAuthenticationFilter" 2 class="com.incoshare.base.security.CustomUsernamePasswordAuthenticationFilter" 3p:authenticationManager-ref="authenticationManager" 4 p:filterProcessesUrl="/doLogin" p:sessionAuthenticationStrategy-ref="compositeSessionAuthenticationStrategy" 5 p:authenticationSuccessHandler-ref="authenticationSuccessHandler" 6 p:authenticationFailureHandler-ref="authenticationFailureHandler" 7p:rememberMeServices-ref="rememberMeServices" 8 p:authenticationDetailsSource-ref="customWebAuthenticationDetailsSource"> 9 </beans:bean> 10 11 12 <beans:bean id="messageSource" 13 class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> 14<beans:property name="basename" 15 value="classpath:messages/security/messages" /> 16 </beans:bean>
配置文件只貼了關鍵部分,第一個bean 配置登錄的過濾器,第二個bean加載messages文件(這裏有需要註意的地方如果想引用自己的message文件,建好文件後提供相對地址就可以了,classpath必須要哦!文件命名也是有規則的,message_en 就是下劃線帶上語言簡稱,這個簡稱需要跟網站上切換中英文標示一致),配置文件就這些
下面貼上過濾器代碼
1 package com.incoshare.base.security; 2 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.http.HttpServletResponse; 5 6 import com.incoshare.base.util.PropertyUtil; 7 import com.incoshare.base.util.Utils; 8 import com.incoshare.incopat4.model.User; 9 import com.incoshare.incopat4.service.usermanager.UserListService; 10 import com.incoshare.util.EncryptUtils; 11 import com.incoshare.util.SingleLoginUtils; 12 import org.slf4j.Logger; 13 import org.slf4j.LoggerFactory; 14 15 import org.springframework.beans.factory.annotation.Autowired; 16 import org.springframework.beans.factory.annotation.Value; 17 import org.springframework.context.i18n.LocaleContextHolder; 18 import org.springframework.security.authentication.AuthenticationServiceException; 19 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 20 import org.springframework.security.core.Authentication; 21 import org.springframework.security.core.AuthenticationException; 22 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 23 import org.springframework.util.StringUtils; 24 import org.springframework.web.servlet.i18n.SessionLocaleResolver; 25 import org.springframework.web.util.WebUtils; 26 27 import com.incoshare.base.util.RegexUtil; 28 29 import java.text.SimpleDateFormat; 30 import java.util.Date; 31 import java.util.Locale; 32 33 public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{ 34 35 static Logger logger = LoggerFactory 36 .getLogger(CustomUsernamePasswordAuthenticationFilter.class); 37 38 private boolean postOnly = true; 39 40 private byte[] keyBytes = { 0x21, 0x12, 0x4F, 0x58, (byte) 0x88, 0x09, 0x40, 0x38, 0x74, 41 0x25, (byte) 0x99, 0x21, (byte) 0xCB, (byte) 0xDD, 0x58, 0x66, 0x77, 0x22, 0x74, 42 (byte) 0x98, 0x30, 0x40, 0x36, (byte) 0xE2 }; 43 private byte[] keyBytesForSjz = { 0x22, 0x12, 0x4F, 0x58, (byte) 0x88, 0x09, 0x40, 0x38, 0x74, 44 0x25, (byte) 0x99, 0x21, (byte) 0xCB, (byte) 0xDD, 0x48, 0x66, 0x77, 0x22, 0x74, 45 (byte) 0x98, 0x30, 0x40, 0x36, (byte) 0xE2 }; 46 @Autowired 47 UserListService userListService; 48 @Autowired 49 PropertyUtil propertyUtil; 50 51 @Override 52 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 53 54 55 String newLocale = request.getParameter("locallangue"); 56 if (newLocale != null) { 57 Locale locale = StringUtils.parseLocaleString(newLocale); 58 WebUtils.setSessionAttribute(request, 59 SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale); 60 LocaleContextHolder.setLocale(locale, true); 61 }
//這塊代碼就是通過獲取前臺返回的語言編碼,設置到spring的localeContextHolder裏 62 if (postOnly && !request.getMethod().equals("POST")) { 63 throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); 64 } 65 66 String username = obtainUsername(request); 67 String password = obtainPassword(request); 68 69 //集慧智佳用戶登錄 70 String token = request.getParameter("token"); 71 //石家莊單點登錄 72 String tokenForSjz = request.getParameter("tokenForSjz"); 73 if(Utils.isNotNull(token) || Utils.isNotNull(tokenForSjz)){ 74 boolean judge = true; 75 if(Utils.isNull(token)){ 76 judge = false; 77 } 78 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH"); 79 Date date = new Date(); 80 String dateStr = simpleDateFormat.format(date); 81 String decodeToken = ""; 82 String decryptJudge = ""; 83 if(judge){ 84 decodeToken = EncryptUtils.DataDecrypt(keyBytes, token); 85 decryptJudge = token; 86 }else{ 87 decodeToken = EncryptUtils.DataDecrypt(keyBytesForSjz, tokenForSjz); 88 decryptJudge = tokenForSjz; 89 }; 90 if(!decodeToken.equals(decryptJudge.trim()) && decodeToken.equals(dateStr.trim())){ 91 92 User user = userListService.queryUserJhzj(username); 93 if(Utils.isNotNull(user)){ 94 if(Utils.isNotNull(user.getOrganizationId())){ 95 if(judge){ 96 String jhzjOrid=propertyUtil.getContextProperty("jhzjOrid"); 97 String pwd = propertyUtil.getContextProperty("jhzjPassword").trim(); 98 if(user.getOrganizationId().equals(Integer.parseInt(jhzjOrid.trim()))){ 99 password = pwd; 100 } 101 }else{ 102 if(Utils.isNotNull(password)){ 103 String record = password; 104 String orid = propertyUtil.getContextProperty("sjzOrid").trim(); 105 password = EncryptUtils.DataDecrypt(keyBytesForSjz,password); 106 if(record.equals(password) || !String.valueOf(user.getOrganizationId()).equals(orid)){ 107 password = ""; 108 } 109 } 110 } 111 112 } 113 } 114 115 }else{ 116 password = ""; 117 } 118 } 119 120 String tokenForLogin = request.getParameter("tokenForLogin"); 121 if(Utils.isNotNull(tokenForLogin)){ 122 String companyName = request.getParameter("companyName"); 123 String record = password; 124 tokenForLogin = tokenForLogin.replaceAll(" ","+"); 125 password = SingleLoginUtils.decryptPassword(username,password,tokenForLogin,companyName,userListService,propertyUtil,logger); 126 if(Utils.isNull(password)){ 127 logger.info("{}:密碼解密為空。賬號{},沒有解密的密碼:{}",companyName,username,record); 128 } 129 } 130 if (username == null) { 131 username = ""; 132 } 133 134 if (password == null) { 135 password = ""; 136 } 137 138 139 username = username.trim(); 140 141 UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); 142 143 if(!StringUtils.isEmpty(request.getParameter("iplogin"))) { 144 username = RegexUtil.getRealIp(request); 145 password=""; 146 authRequest = new IpUserAuthenticationToken(username,password); 147 } 148 149 this.logger.info("user:{},ip:{} trying to login",new Object[]{username,RegexUtil.getRealIp(request)}); 150 151 // Allow subclasses to set the "details" property 152 setDetails(request, authRequest); 153 154 return this.getAuthenticationManager().authenticate(authRequest); 155 } 156 }
這塊先聲明下,代碼不是我寫的,看著很亂很糟糕吧。主要上邊標黃的兩個地方就可以了。
值設置後會通過this.getAuthenticationManager().authenticate(authRequest) 去初始化,喜歡研究源碼的朋友看一跟一下看看
org.springframework.context.i18n.LocaleContextHolder這個類
1 public static LocaleContext getLocaleContext() { 2 LocaleContext localeContext = localeContextHolder.get(); 3 if (localeContext == null) { 4 localeContext = inheritableLocaleContextHolder.get();//這裏會把你設置的值放到Spring 容器 5 } 6 return localeContext; 7 }
好了,關鍵的地方都說完了,這幾天搞了這麽久,寫完了也沒多少東西,代碼就是這麽美妙,解決問題的過程是漫長苦惱的,但最終解決有可能就一兩行代碼的事。
關於這一塊有問題的可以隨時溝通。
Spring security實現國際化問題