Spring security实现国际化问题
Posted boboxing2017
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring security实现国际化问题相关的知识,希望对你有一定的参考价值。
这两天Spring用户登录国际化这个问题困扰我好久啊,于昨天晚上终于把它干掉了。
场景就是我们公司的产品-incopat,需要支持中英文,用户登录这块用的spring自带的security,需求讲的通俗一点就是,中文版提示中文提示信息,英文版提示英文版信息,废话不多说,见代码。
首先配置文件
security-config.xml
1 <beans:bean id="customUsernamePasswordAuthenticationFilter" 2 class="com.incoshare.base.security.CustomUsernamePasswordAuthenticationFilter" 3 p:authenticationManager-ref="authenticationManager" 4 p:filterProcessesUrl="/doLogin" p:sessionAuthenticationStrategy-ref="compositeSessionAuthenticationStrategy" 5 p:authenticationSuccessHandler-ref="authenticationSuccessHandler" 6 p:authenticationFailureHandler-ref="authenticationFailureHandler" 7 p: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实现国际化问题的主要内容,如果未能解决你的问题,请参考以下文章
允许 URL 中的语言参数(Spring Boot / Security)
springboot集成spring security实现restful风格的登录认证 附代码
如何为登录GRAILS(Spring security)的用户实现会话?