文章目录
项目源码地址 https://github.com/nieandsun/security
1. 自定义登陆成功/登陆失败优化
本篇文章是在上篇文章基础上写的,这里的优化逻辑为:
① 定义两个标记如
JSON-------表示登陆成功后的处理行为为返回一个JSON,
REDIRECT---表示登陆成功后的处理行为为spring-security默认的处理行为即登录成功后会跳转到引发登录的请求上
② 将定义的两个标记弄成在yml或properties里可配置的选项
③ 后端根据上面定义的两个标记进行判断处理和代码实现
④ 其他开发人员通过配置不同的标记来选择不同的登陆成功后的处理行为
1.1 定义处理登陆成功后不同处理行为的标记
- 定义标记---------封装到一个枚举里
package com.nrsc.security.core.properties;
/**
* 处理成功和处理失败可以有不同的方式,这里做个简单处理,要么都为REDIRECT,要么都为JSON
* Created By: Sun Chuan
* Created Date: 2019/6/20 22:15
*/
public enum LoginType {
/**
* 返回标记
* 表示按照spring-security默认方式即:登录成功后会跳转到引发登录的请求上
*/
REDIRECT,
/**
* 返回标记
* 表示登陆成功,返回json字符串
*/
JSON
}
1.2将定义的两个标记弄成在yml或properties里可配置的选项
- 将定义的两个标记封装到BrowserProperties
package com.nrsc.security.core.properties;
import lombok.Data;
/**
* Created By: Sun Chuan
* Created Date: 2019/6/20 22:13
*/
@Data
public class BrowserProperties {
//指定默认的登陆页面
private String loginPage = "/nrsc-login.html";
//指定默认的处理成功与处理失败的方法
private LoginType loginType = LoginType.JSON;
}
- 定义统一管理项目中所有由yml或properties文件传入的变量的类
package com.nrsc.security.core.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* "大盒子"类-----------------用于统一管理项目中所有由yml或properties文件传入的变量值
* Created By: Sun Chuan
* Created Date: 2019/6/20 22:13
*/
@Component //将此类注入到spring容器中
@Data //不用写get set方法了
@ConfigurationProperties(prefix = "nrsc.security") //指定以nrsc.security开头的配置会射入到该类中
public class SecurityProperties {
//封装浏览器相关的属性
private BrowserProperties browser = new BrowserProperties();
}
- yml中的配置
nrsc:
security:
browser:
loginPage: /OtherServer/other-login.html
loginType: REDIRECT
1.3 根据定义的两个标记进行登陆成功后行为的不同实现
由于我们想做的是如果获得配置文件里传入的为JSON标记或者用户未传任何与之相关标记,登陆成功后就返回JSON;如果配置文件里传入的为REDIRECT,我们就按照spring-security默认的逻辑:登录成功后会跳转到引发登录的请求上,因此我们可以不再实现AuthenticationSuccessHandler接口,而是继承spring-security中实现了AuthenticationSuccessHandler接口的类,如果我们获得的标记为JSON,就走我们之前定义的逻辑:返回JSON数据;如果获得的标记为REDIRECT,就直接调用spring-security中实现了AuthenticationSuccessHandler接口的类中的方法.
下图为所有实现了AuthenticationSuccessHandler接口的类,我这里选择的是SavedRequestAwareAuthenticationSuccessHandler,大家可以试试其他的类
具体实现如下:
package com.nrsc.security.browser.beans;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nrsc.security.core.properties.LoginType;
import com.nrsc.security.core.properties.SecurityProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created By: Sun Chuan
* Created Date: 2019/6/18 19:32
*/
@Slf4j
@Component(value = "NRSCAuthenticationSuccessHandler")
public class NRSCAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SecurityProperties securityProperties;
/**
* Authentication封装了用户认证成功的信息
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication)
throws IOException, ServletException {
log.info("登陆成功");
//如果设置了登陆成功返回json,则按如下方式进行返回
if (LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())) {
//设置返回内容的数据形式和编码格式
httpServletResponse.setContentType("application/json;charset=UTF-8");
//将户认证成功的信息以json数据的形式返回给前端
httpServletResponse.getWriter().write(objectMapper.writeValueAsString(authentication));
} else {
//如果登陆成功后不想返回json,可以按照spring-security默认方式进行处理(登录成功后会跳转到引发登录的请求上)
super.onAuthenticationSuccess(httpServletRequest, httpServletResponse, authentication);
}
}
}
2 测试
2.1 配置文件里配置REDIRECT时
2.2 配置文件里配置JSON或不在配置文件里进行任何相关配置时
登陆失败优化的测试可以下载源码后自己进行测试:https://github.com/nieandsun/security