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实现国际化问题的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security简明实践及相关国际化处理

允许 URL 中的语言参数(Spring Boot / Security)

springboot集成spring security实现restful风格的登录认证 附代码

如何为登录GRAILS(Spring security)的用户实现会话?

如何创建数据类实现 Spring Security 特定的 UserDetails

Spring Security---验证码详解