Merge branch 'develop' of https://gitee.com/saturneric/ASE
This commit is contained in:
commit
34e9455ad9
@ -0,0 +1,14 @@
|
|||||||
|
package com.codesdream.ase.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AJAXRequestChecker {
|
||||||
|
public boolean checkAjaxPOSTRequest(HttpServletRequest request){
|
||||||
|
return Optional.ofNullable(request.getHeader("X-Requested-With")).isPresent();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.codesdream.ase.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AuthTokenGenerator {
|
||||||
|
@Resource
|
||||||
|
private SHA1Encoder encoder;
|
||||||
|
|
||||||
|
public String generateAuthToken(String username){
|
||||||
|
Date dateNow = new Date();
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
return encoder.encode(String.format("Token [%s][%d][%s]",username,dateNow.getTime(), uuid.toString()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.codesdream.ase.component.auth;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
// 随机特征码生成器
|
||||||
|
@Component
|
||||||
|
public class JSONRandomCodeGenerator {
|
||||||
|
@Resource
|
||||||
|
private SHA1Encoder encoder;
|
||||||
|
|
||||||
|
public String generateRandomCode(String username, Date date, String clientCode){
|
||||||
|
return encoder.encode(String.format("RandomCode [%s][%s][%s]",
|
||||||
|
username, Long.toString(date.getTime()), clientCode));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.codesdream.ase.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
// 用来给JSON生成签名
|
||||||
|
@Component
|
||||||
|
public class JSONSignedGenerator {
|
||||||
|
@Resource
|
||||||
|
SHA1Encoder encoder;
|
||||||
|
|
||||||
|
public String generateSigned(String username, String randomCode, String token){
|
||||||
|
return encoder.encode(String.format("SIGN [%s][%s][%s]",username, randomCode, token));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package com.codesdream.ase.component.auth;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
// 关联Token与其他用户的相关数据的授权柄
|
||||||
|
public class JSONTokenAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
|
// 客户端签名
|
||||||
|
private String signed = null;
|
||||||
|
// 用户名
|
||||||
|
private Object principal = null;
|
||||||
|
// 客户端代码
|
||||||
|
private String clientCode = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a token with the supplied array of authorities.
|
||||||
|
*
|
||||||
|
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the principal
|
||||||
|
* represented by this authentication object.
|
||||||
|
*/
|
||||||
|
public JSONTokenAuthenticationToken(UserDetails principal,
|
||||||
|
String clientCode,
|
||||||
|
Collection<? extends GrantedAuthority> authorities)
|
||||||
|
{
|
||||||
|
super(authorities);
|
||||||
|
this.principal = principal;
|
||||||
|
this.clientCode = clientCode;
|
||||||
|
this.signed = null;
|
||||||
|
setAuthenticated(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONTokenAuthenticationToken(String principal, String clientCode, String signed) {
|
||||||
|
super(null);
|
||||||
|
this.principal = principal;
|
||||||
|
this.clientCode = clientCode;
|
||||||
|
this.signed = signed;
|
||||||
|
setAuthenticated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCredentials() {
|
||||||
|
return signed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientCode() {
|
||||||
|
return clientCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientCode(String clientCode) {
|
||||||
|
this.clientCode = clientCode;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.codesdream.ase.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
// 明文用户名密码验证授权柄
|
||||||
|
public class JSONTokenUsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
|
// 用户名
|
||||||
|
private String username = null;
|
||||||
|
// 明文密码
|
||||||
|
private String password = null;
|
||||||
|
// 授权柄
|
||||||
|
private String clientCode = null;
|
||||||
|
|
||||||
|
public JSONTokenUsernamePasswordAuthenticationToken(String username, String password, String clientCode) {
|
||||||
|
super(null);
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.clientCode = clientCode;
|
||||||
|
setAuthenticated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCredentials() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
// 扩展接口 获得客户端代码
|
||||||
|
public String getClientCode() {
|
||||||
|
return clientCode;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.codesdream.ase.component.auth;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.cli.Digest;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
// SHA1算法不可逆加密 主要用于JSON签名
|
||||||
|
@Component
|
||||||
|
public class SHA1Encoder {
|
||||||
|
String encode(CharSequence charSequence){
|
||||||
|
return DigestUtils.sha1Hex(charSequence.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean match(CharSequence charSequence, String s){
|
||||||
|
return s.equals(encode(charSequence));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.codesdream.ase.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
// 验证时间戳是否有效
|
||||||
|
@Component
|
||||||
|
public class TimestampExpiredChecker {
|
||||||
|
|
||||||
|
public boolean checkTimestampBeforeMaxTime(String timestamp, int seconds){
|
||||||
|
Date timestampDate = new Date(Long.parseLong(timestamp));
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
Date maxDate = new Date(currentTime + seconds * 1000);
|
||||||
|
return timestampDate.before(maxDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,9 +2,11 @@ package com.codesdream.ase.component.datamanager;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.codesdream.ase.component.json.respond.JSONBaseRespondObject;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@ -19,7 +21,13 @@ public class JSONParameter {
|
|||||||
// 处理Request Body
|
// 处理Request Body
|
||||||
public String getRequestBody(HttpServletRequest request){
|
public String getRequestBody(HttpServletRequest request){
|
||||||
try {
|
try {
|
||||||
return request.getParameter("json");
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
BufferedReader reader = request.getReader();
|
||||||
|
reader.reset();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null)
|
||||||
|
stringBuilder.append(line);
|
||||||
|
return stringBuilder.toString();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
@ -50,6 +58,44 @@ public class JSONParameter {
|
|||||||
return JSON.toJSONString(object);
|
return JSON.toJSONString(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据对象构造获得标准的JSON响应字符串返回
|
||||||
|
public String getJSONStandardRespond(Integer status, String msg, Object dataObject){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(status, msg);
|
||||||
|
respondObject.setData(dataObject);
|
||||||
|
return getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得标准的JSON响应字符串返回(404状态)
|
||||||
|
public String getJSONStandardRespond404(String msg){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(404, msg);
|
||||||
|
return getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得标准的JSON响应字符串返回(500状态)
|
||||||
|
public String getJSONStandardRespond500(String msg){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(500, msg);
|
||||||
|
return getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得标准的JSON响应字符串返回(200状态)
|
||||||
|
public String getJSONStandardRespond200(Object dataObject){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(200, "ok");
|
||||||
|
respondObject.setData(dataObject);
|
||||||
|
return getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得标准的JSON响应字符串返回(403状态)
|
||||||
|
public String getJSONStandardRespond403(){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(403, "Forbidden");
|
||||||
|
return getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得标准的JSON响应字符串返回(401状态)
|
||||||
|
public String getJSONStandardRespond401(){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(401, "Unauthorized");
|
||||||
|
return getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
// 由JSON对象获得对应的Java对象
|
// 由JSON对象获得对应的Java对象
|
||||||
public <T> T getJavaObject(JSONObject json, Class<T> type){
|
public <T> T getJavaObject(JSONObject json, Class<T> type){
|
||||||
return json.toJavaObject(type);
|
return json.toJavaObject(type);
|
||||||
@ -61,4 +107,6 @@ public class JSONParameter {
|
|||||||
return json.map(jsonObject -> getJavaObject(jsonObject, type));
|
return json.map(jsonObject -> getJavaObject(jsonObject, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.codesdream.ase.component.json;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
// 所有有效的JSON对象模板
|
||||||
|
@Slf4j
|
||||||
|
public class JSONBaseObject {
|
||||||
|
Date time = new Date();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.codesdream.ase.component.json.request;
|
||||||
|
|
||||||
|
import com.codesdream.ase.component.json.JSONBaseObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
// 客户端请求的JSON模板
|
||||||
|
@Slf4j
|
||||||
|
public class JSONBaseRequestObject extends JSONBaseObject {
|
||||||
|
String signed;
|
||||||
|
|
||||||
|
}
|
@ -4,7 +4,10 @@ import lombok.Data;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class UserLoginChecker {
|
public class UserLoginChecker {
|
||||||
|
// 请求类型
|
||||||
private String checkType;
|
private String checkType;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
private String clientCode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.codesdream.ase.component.json.respond;
|
||||||
|
|
||||||
|
public class EmptyDataObjectRespond {
|
||||||
|
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
package com.codesdream.ase.component.json.respond;
|
|
||||||
|
|
||||||
// 请求失败返回JSON
|
|
||||||
public class FailedSONRespond extends JSONBaseRespondObject {
|
|
||||||
public FailedSONRespond(){
|
|
||||||
super();
|
|
||||||
this.status = "fail";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +1,58 @@
|
|||||||
package com.codesdream.ase.component.json.respond;
|
package com.codesdream.ase.component.json.respond;
|
||||||
|
|
||||||
|
import com.codesdream.ase.component.json.JSONBaseObject;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
// 服务端返回的JSON对象基础信息
|
// 服务端返回的JSON对象模板
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
public class JSONBaseRespondObject {
|
public class JSONBaseRespondObject extends JSONBaseObject {
|
||||||
// 请求成功状态
|
|
||||||
String status = "fail";
|
|
||||||
// 时间
|
|
||||||
Date time = new Date();
|
|
||||||
|
|
||||||
public JSONBaseRespondObject(){
|
// 存放返回内容
|
||||||
|
private Object data = new EmptyDataObjectRespond();
|
||||||
|
|
||||||
|
// 存放响应信息提示
|
||||||
|
private String msg = "";
|
||||||
|
|
||||||
|
// 状态
|
||||||
|
private Integer status = 200;
|
||||||
|
|
||||||
|
public JSONBaseRespondObject(String msg){
|
||||||
|
super();
|
||||||
|
this.status = 200;
|
||||||
|
this.msg = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONBaseRespondObject(String status){
|
public JSONBaseRespondObject(Integer status, String msg){
|
||||||
|
super();
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusNotFound(){
|
||||||
|
this.status = 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusBadRequest(){
|
||||||
|
this.status = 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusUnauthorized(){
|
||||||
|
this.status = 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusForbidden(){
|
||||||
|
this.status = 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusInternalServerError(){
|
||||||
|
this.status = 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusOK(){
|
||||||
|
this.status = 200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.codesdream.ase.component.json.respond;
|
||||||
|
|
||||||
|
// 请求失败返回JSON
|
||||||
|
public class JSONStandardFailedRespond extends JSONBaseRespondObject {
|
||||||
|
public JSONStandardFailedRespond(){
|
||||||
|
super(500, "failed");
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,15 @@
|
|||||||
package com.codesdream.ase.component.json.respond;
|
package com.codesdream.ase.component.json.respond;
|
||||||
|
|
||||||
|
import com.sun.org.apache.xpath.internal.operations.Bool;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@Data
|
@Data
|
||||||
public class UserLoginCheckerJSONRespond extends JSONBaseRespondObject {
|
public class UserLoginCheckerJSONRespond {
|
||||||
boolean userExist = false;
|
Boolean userExist = null;
|
||||||
boolean loginStatus = false;
|
Boolean userBanned = null;
|
||||||
boolean userBanned = false;
|
Boolean loginStatus = null;
|
||||||
String respondInformation = "";
|
String respondInformation = "";
|
||||||
String sessionId = "";
|
String token = null;
|
||||||
|
|
||||||
public UserLoginCheckerJSONRespond(){
|
|
||||||
super("success");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.codesdream.ase.component.json.respond;
|
||||||
|
|
||||||
|
// 返回登录后的授权码(用于客户端生成签名)
|
||||||
|
public class UserLoginTokenJSONRespond {
|
||||||
|
String token;
|
||||||
|
}
|
@ -26,15 +26,9 @@ public class ASEAccessDeniedHandler implements AccessDeniedHandler {
|
|||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
log.info("ASEAccessDeniedHandler Found!");
|
log.info("ASEAccessDeniedHandler Found!");
|
||||||
|
|
||||||
response.setCharacterEncoding("utf-8");
|
// 对无权限操作返回403
|
||||||
response.setContentType("text/javascript;charset=utf-8");
|
response.getWriter().print(jsonParameter.getJSONStandardRespond403());
|
||||||
UserLoginCheckerJSONRespond checkerRespond = new UserLoginCheckerJSONRespond();
|
|
||||||
checkerRespond.setLoginStatus(true);
|
|
||||||
checkerRespond.setUserExist(true);
|
|
||||||
checkerRespond.setRespondInformation("Authenticated user has no access to this resource");
|
|
||||||
|
|
||||||
// 对匿名用户返回
|
|
||||||
response.getWriter().print(jsonParameter.getJSONString(checkerRespond));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.codesdream.ase.component.permission;
|
package com.codesdream.ase.component.permission;
|
||||||
|
|
||||||
import com.codesdream.ase.component.datamanager.JSONParameter;
|
import com.codesdream.ase.component.datamanager.JSONParameter;
|
||||||
|
import com.codesdream.ase.component.json.respond.JSONBaseRespondObject;
|
||||||
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
|
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
@ -23,18 +24,8 @@ public class ASEAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
|||||||
@Override
|
@Override
|
||||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
log.info("ASEAuthenticationEntryPoint Found!");
|
// 对匿名用户返回401
|
||||||
|
response.getWriter().print(jsonParameter.getJSONStandardRespond401());
|
||||||
response.setCharacterEncoding("utf-8");
|
|
||||||
response.setContentType("text/javascript;charset=utf-8");
|
|
||||||
UserLoginCheckerJSONRespond checkerRespond = new UserLoginCheckerJSONRespond();
|
|
||||||
checkerRespond.setLoginStatus(false);
|
|
||||||
checkerRespond.setUserExist(false);
|
|
||||||
checkerRespond.setUserBanned(true);
|
|
||||||
checkerRespond.setRespondInformation("Anonymous user has no access to this resource");
|
|
||||||
|
|
||||||
// 对匿名用户返回
|
|
||||||
response.getWriter().print(jsonParameter.getJSONString(checkerRespond));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,16 +23,17 @@ public class ASEAuthenticationFailureHandler extends SimpleUrlAuthenticationFail
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
|
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
|
||||||
throws IOException, ServletException
|
throws IOException
|
||||||
{
|
{
|
||||||
log.info("ASEAuthenticationSuccessHandler Login Fail!");
|
log.info("ASEAuthenticationFailureHandler Login Fail!");
|
||||||
UserLoginCheckerJSONRespond respond = new UserLoginCheckerJSONRespond();
|
UserLoginCheckerJSONRespond respond = new UserLoginCheckerJSONRespond();
|
||||||
respond.setUserExist(false);
|
|
||||||
|
respond.setUserExist(null);
|
||||||
|
respond.setUserBanned(null);
|
||||||
respond.setLoginStatus(false);
|
respond.setLoginStatus(false);
|
||||||
respond.setUserBanned(true);
|
|
||||||
respond.setRespondInformation("Authentication Failed");
|
respond.setRespondInformation("Authentication Failed");
|
||||||
|
|
||||||
// 填充response对象
|
// 填充response对象
|
||||||
response.getWriter().write(jsonParameter.getJSONString(respond));
|
response.getWriter().write(jsonParameter.getJSONStandardRespond200(respond));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
package com.codesdream.ase.component.permission;
|
package com.codesdream.ase.component.permission;
|
||||||
|
|
||||||
|
import com.codesdream.ase.component.auth.JSONTokenAuthenticationToken;
|
||||||
import com.codesdream.ase.component.datamanager.JSONParameter;
|
import com.codesdream.ase.component.datamanager.JSONParameter;
|
||||||
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
|
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
|
||||||
import com.codesdream.ase.model.permission.User;
|
import com.codesdream.ase.model.permission.User;
|
||||||
|
|
||||||
|
import com.codesdream.ase.service.IAuthService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@ -26,31 +29,33 @@ public class ASEAuthenticationSuccessHandler extends SavedRequestAwareAuthentica
|
|||||||
@Resource
|
@Resource
|
||||||
private JSONParameter jsonParameter;
|
private JSONParameter jsonParameter;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IAuthService authService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||||
throws IOException, ServletException
|
throws IOException, ServletException
|
||||||
{
|
{
|
||||||
// 对AJAX登录请求特殊化处理
|
|
||||||
if(Optional.ofNullable(request.getHeader("X-Requested-With")).isPresent()) {
|
|
||||||
HttpSession session = request.getSession();
|
|
||||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
|
||||||
|
|
||||||
session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打印用户登录成功日志
|
|
||||||
log.info(String.format("ASEAuthenticationSuccessHandler: %s Login Success.",
|
|
||||||
((User)authentication.getDetails()).getUsername()));
|
|
||||||
|
|
||||||
UserLoginCheckerJSONRespond respond = new UserLoginCheckerJSONRespond();
|
UserLoginCheckerJSONRespond respond = new UserLoginCheckerJSONRespond();
|
||||||
respond.setUserExist(authentication.isAuthenticated());
|
respond.setUserExist(authentication.isAuthenticated());
|
||||||
respond.setLoginStatus(authentication.isAuthenticated());
|
respond.setLoginStatus(authentication.isAuthenticated());
|
||||||
|
respond.setRespondInformation("Authentication Success");
|
||||||
|
|
||||||
// 获得session id
|
// 获得 JSONTokenAuthenticationToken
|
||||||
WebAuthenticationDetails webAuthenticationDetails = (WebAuthenticationDetails) (authentication.getDetails());
|
JSONTokenAuthenticationToken authenticationToken = (JSONTokenAuthenticationToken) authentication;
|
||||||
respond.setSessionId(webAuthenticationDetails.getSessionId());
|
|
||||||
|
|
||||||
response.getWriter().write(jsonParameter.getJSONString(respond));
|
User user = (User) authenticationToken.getPrincipal();
|
||||||
|
|
||||||
|
Optional<String> tokenOptional = authService.userNewTokenGetter(
|
||||||
|
user.getUsername(), authenticationToken.getClientCode());
|
||||||
|
|
||||||
|
if(tokenOptional.isPresent()){
|
||||||
|
respond.setToken(tokenOptional.get());
|
||||||
|
}
|
||||||
|
else respond.setToken("");
|
||||||
|
|
||||||
|
response.getWriter().write(jsonParameter.getJSONStandardRespond200(respond));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,119 @@
|
|||||||
|
package com.codesdream.ase.component.permission;
|
||||||
|
|
||||||
|
import com.codesdream.ase.component.auth.AJAXRequestChecker;
|
||||||
|
import com.codesdream.ase.component.auth.JSONRandomCodeGenerator;
|
||||||
|
import com.codesdream.ase.component.auth.JSONSignedGenerator;
|
||||||
|
import com.codesdream.ase.component.auth.JSONTokenAuthenticationToken;
|
||||||
|
import com.codesdream.ase.component.datamanager.JSONParameter;
|
||||||
|
import com.codesdream.ase.model.auth.JSONToken;
|
||||||
|
import com.codesdream.ase.service.AuthService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
|
// API请求验证过滤
|
||||||
|
@Slf4j
|
||||||
|
public class ASEJSONTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JSONParameter jsonParameter;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JSONRandomCodeGenerator randomCodeGenerator;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AJAXRequestChecker ajaxRequestChecker;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AuthService authService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JSONSignedGenerator signedGenerator;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
// 用户名
|
||||||
|
String username = request.getHeader( "username");
|
||||||
|
// 客户端签名
|
||||||
|
String signed = request.getHeader("signed");
|
||||||
|
// 时间戳
|
||||||
|
String timestamp = request.getHeader("timestamp");
|
||||||
|
|
||||||
|
if (signed != null && username != null && timestamp != null) {
|
||||||
|
// 获得具体时间
|
||||||
|
Date date = new Date(Long.parseLong(timestamp));
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
// 限制时间戳有效区间为60s
|
||||||
|
long dtTime = 60*1000;
|
||||||
|
Date maxDate = new Date(now.getTime() + dtTime);
|
||||||
|
|
||||||
|
// 检查时间戳是否合理
|
||||||
|
if(maxDate.after(date)) {
|
||||||
|
// 从服务器中查找token
|
||||||
|
Optional<JSONToken> optionalJSONToken = authService.findTokenByUserName(username);
|
||||||
|
if (optionalJSONToken.isPresent()) {
|
||||||
|
JSONToken token = optionalJSONToken.get();
|
||||||
|
|
||||||
|
// 检查token是否过期
|
||||||
|
if (!authService.checkTokenIfExpired(token)) {
|
||||||
|
// 生成特征随机代码
|
||||||
|
String randomCode = randomCodeGenerator.generateRandomCode(username, date, token.getClientCode());
|
||||||
|
|
||||||
|
log.info(String.format("Determined Signed: %s",
|
||||||
|
signedGenerator.generateSigned(username, randomCode, token.getToken())));
|
||||||
|
|
||||||
|
// 检查签名是否正确
|
||||||
|
if (signed.equals(signedGenerator.generateSigned(username, randomCode, token.getToken()))) {
|
||||||
|
// 执行授权操作
|
||||||
|
doAuthentication(username, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行授权
|
||||||
|
private void doAuthentication(String username, HttpServletRequest request){
|
||||||
|
// 查询用户的相关信息
|
||||||
|
UserDetails user = userDetailsService.loadUserByUsername(username);
|
||||||
|
|
||||||
|
// 生成用户权限列表
|
||||||
|
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
|
||||||
|
|
||||||
|
// 生成授权柄 (储存上下文信息)
|
||||||
|
JSONTokenAuthenticationToken authentication =
|
||||||
|
new JSONTokenAuthenticationToken(user, null, authorities);
|
||||||
|
|
||||||
|
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
|
||||||
|
// 执行授权
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package com.codesdream.ase.component.permission;
|
package com.codesdream.ase.component.permission;
|
||||||
|
|
||||||
|
import com.codesdream.ase.component.auth.JSONTokenAuthenticationToken;
|
||||||
|
import com.codesdream.ase.component.auth.JSONTokenUsernamePasswordAuthenticationToken;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.authentication.*;
|
import org.springframework.security.authentication.*;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
@ -14,6 +16,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
// 普通用户名密码验证, 用户获得Token
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class ASESecurityAuthenticationProvider implements AuthenticationProvider {
|
public class ASESecurityAuthenticationProvider implements AuthenticationProvider {
|
||||||
@ -28,10 +31,15 @@ public class ASESecurityAuthenticationProvider implements AuthenticationProvider
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
JSONTokenUsernamePasswordAuthenticationToken authenticationToken =
|
||||||
|
(JSONTokenUsernamePasswordAuthenticationToken) authentication;
|
||||||
|
|
||||||
// 获得登录表单中的学号
|
// 获得登录表单中的学号
|
||||||
String username = usernameEncoder.encode(authentication.getName());
|
String username = usernameEncoder.encode((CharSequence) authenticationToken.getPrincipal());
|
||||||
// 获得表单中的密码
|
// 获得表单中的密码
|
||||||
String password = passwordEncoder.encode(authentication.getCredentials().toString());
|
String password = passwordEncoder.encode((CharSequence) authenticationToken.getCredentials());
|
||||||
|
// 获得
|
||||||
|
String clientCode = authenticationToken.getClientCode();
|
||||||
// 判断用户是否存在
|
// 判断用户是否存在
|
||||||
UserDetails userInfo = userDetailsService.loadUserByUsername(username);
|
UserDetails userInfo = userDetailsService.loadUserByUsername(username);
|
||||||
|
|
||||||
@ -57,12 +65,14 @@ public class ASESecurityAuthenticationProvider implements AuthenticationProvider
|
|||||||
throw new AccountExpiredException("User IS Expired");
|
throw new AccountExpiredException("User IS Expired");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 生成权限列表
|
||||||
Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
|
Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
|
||||||
return new UsernamePasswordAuthenticationToken(userInfo, password, authorities);
|
|
||||||
|
return new JSONTokenAuthenticationToken(userInfo, clientCode, authorities);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(Class<?> aClass) {
|
public boolean supports(Class<?> aClass) {
|
||||||
return true;
|
return aClass.equals(JSONTokenUsernamePasswordAuthenticationToken.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.codesdream.ase.component.permission;
|
package com.codesdream.ase.component.permission;
|
||||||
|
|
||||||
|
import com.codesdream.ase.component.auth.AJAXRequestChecker;
|
||||||
|
import com.codesdream.ase.component.auth.JSONTokenUsernamePasswordAuthenticationToken;
|
||||||
|
import com.codesdream.ase.component.auth.TimestampExpiredChecker;
|
||||||
import com.codesdream.ase.component.datamanager.JSONParameter;
|
import com.codesdream.ase.component.datamanager.JSONParameter;
|
||||||
import com.codesdream.ase.component.json.request.UserLoginChecker;
|
import com.codesdream.ase.component.json.request.UserLoginChecker;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -9,6 +12,8 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
|||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@ -22,41 +27,52 @@ public class ASEUsernamePasswordAuthenticationFilter extends UsernamePasswordAut
|
|||||||
@Resource
|
@Resource
|
||||||
private JSONParameter jsonParameter;
|
private JSONParameter jsonParameter;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AJAXRequestChecker ajaxRequestChecker;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TimestampExpiredChecker timestampExpiredChecker;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws AuthenticationException {
|
throws AuthenticationException {
|
||||||
|
|
||||||
|
String timestamp = request.getHeader("timestamp");
|
||||||
|
|
||||||
|
// 检查时间戳是否合理(60秒内)
|
||||||
|
if(!timestampExpiredChecker.checkTimestampBeforeMaxTime(timestamp, 60)){
|
||||||
|
throw new AuthenticationServiceException("Timestamp Expired.");
|
||||||
|
}
|
||||||
|
|
||||||
// 判断是否为AJAX请求格式的数据
|
// 判断是否为AJAX请求格式的数据
|
||||||
if(Optional.ofNullable(request.getHeader("X-Requested-With")).isPresent()) {
|
if(!ajaxRequestChecker.checkAjaxPOSTRequest(request)) {
|
||||||
|
throw new AuthenticationServiceException("Authentication method not supported: NOT Ajax Method.");
|
||||||
Optional<UserLoginChecker> checker = jsonParameter.getJavaObjectByRequest(request, UserLoginChecker.class);
|
|
||||||
if(!checker.isPresent()) throw new BadCredentialsException("Invalid AJAX JSON Request");
|
|
||||||
if (!checker.get().getCheckType().equals("From"))
|
|
||||||
throw new AuthenticationServiceException("Invalid Checker Type");
|
|
||||||
|
|
||||||
// 获得相应的用户名密码
|
|
||||||
String username = checker.get().getUsername();
|
|
||||||
String password = checker.get().getPassword();
|
|
||||||
|
|
||||||
if (username == null) username = "";
|
|
||||||
if (password == null) password = "";
|
|
||||||
|
|
||||||
// 去除首尾两端的空白字符
|
|
||||||
username = username.trim();
|
|
||||||
password = password.trim();
|
|
||||||
|
|
||||||
UsernamePasswordAuthenticationToken authRequest =
|
|
||||||
new UsernamePasswordAuthenticationToken(username, password);
|
|
||||||
|
|
||||||
|
|
||||||
log.info(String.format("User AJAX JSON Authentication: %s %s.", username, password));
|
|
||||||
|
|
||||||
setDetails(request, authRequest);
|
|
||||||
|
|
||||||
return this.getAuthenticationManager().authenticate(authRequest);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return super.attemptAuthentication(request, response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional<UserLoginChecker> checker = jsonParameter.getJavaObjectByRequest(request, UserLoginChecker.class);
|
||||||
|
if(!checker.isPresent()) throw new BadCredentialsException("Invalid AJAX JSON Request");
|
||||||
|
|
||||||
|
if (!checker.get().getCheckType().equals("UsernamePasswordChecker"))
|
||||||
|
throw new AuthenticationServiceException("Authentication not supported: NOT Username Password Type.");
|
||||||
|
|
||||||
|
// 获得相应的用户名密码
|
||||||
|
String username = checker.get().getUsername();
|
||||||
|
String password = checker.get().getPassword();
|
||||||
|
String clientCode = checker.get().getClientCode();
|
||||||
|
|
||||||
|
if (username == null) username = "";
|
||||||
|
if (password == null) password = "";
|
||||||
|
|
||||||
|
// 去除首尾两端的空白字符
|
||||||
|
username = username.trim();
|
||||||
|
password = password.trim();
|
||||||
|
|
||||||
|
|
||||||
|
JSONTokenUsernamePasswordAuthenticationToken authRequest =
|
||||||
|
new JSONTokenUsernamePasswordAuthenticationToken(username, password, clientCode);
|
||||||
|
|
||||||
|
authRequest.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
|
||||||
|
return this.getAuthenticationManager().authenticate(authRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.codesdream.ase.component.permission.*;
|
|||||||
import com.codesdream.ase.service.ASEUserDetailsService;
|
import com.codesdream.ase.service.ASEUserDetailsService;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
@ -51,6 +52,7 @@ public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
@Resource
|
@Resource
|
||||||
ASEAccessDeniedHandler accessDeniedHandler;
|
ASEAccessDeniedHandler accessDeniedHandler;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
@ -66,7 +68,9 @@ public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
|
|
||||||
// 替换掉原有的UsernamePasswordAuthenticationFilter
|
// 替换掉原有的UsernamePasswordAuthenticationFilter
|
||||||
http.addFilterAt(aseUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
http.addFilterAt(aseUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||||
.addFilterAfter(new SecurityContextPersistenceFilter(), UsernamePasswordAuthenticationFilter.class);
|
.addFilterBefore(asejsonTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||||
|
|
||||||
|
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +94,12 @@ public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
"/login/**");
|
"/login/**");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//注册自定义的UsernamePasswordAuthenticationFilter
|
||||||
|
@Bean
|
||||||
|
ASEJSONTokenAuthenticationFilter asejsonTokenAuthenticationFilter() throws Exception {
|
||||||
|
return new ASEJSONTokenAuthenticationFilter();
|
||||||
|
}
|
||||||
|
|
||||||
//注册自定义的UsernamePasswordAuthenticationFilter
|
//注册自定义的UsernamePasswordAuthenticationFilter
|
||||||
@Bean
|
@Bean
|
||||||
ASEUsernamePasswordAuthenticationFilter aseUsernamePasswordAuthenticationFilter() throws Exception {
|
ASEUsernamePasswordAuthenticationFilter aseUsernamePasswordAuthenticationFilter() throws Exception {
|
||||||
@ -99,7 +109,7 @@ public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy(sessionRegistry()));
|
filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy(sessionRegistry()));
|
||||||
filter.setAllowSessionCreation(true);
|
filter.setAllowSessionCreation(true);
|
||||||
filter.setRequiresAuthenticationRequestMatcher(
|
filter.setRequiresAuthenticationRequestMatcher(
|
||||||
new AntPathRequestMatcher("/login/process", "POST"));
|
new AntPathRequestMatcher("/login/token", "POST"));
|
||||||
|
|
||||||
filter.setAuthenticationManager(authenticationManagerBean());
|
filter.setAuthenticationManager(authenticationManagerBean());
|
||||||
return filter;
|
return filter;
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.codesdream.ase.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class APIController {
|
||||||
|
|
||||||
|
@RequestMapping("hello")
|
||||||
|
String hello(){
|
||||||
|
return "hello";
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ import java.util.List;
|
|||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class ASEErrorController implements ErrorController {
|
public class ASEErrorController implements ErrorController {
|
||||||
|
|
||||||
@RequestMapping("/error")
|
@RequestMapping("/error")
|
||||||
public String handleError(HttpServletRequest request, Model model){
|
public String handleError(HttpServletRequest request, Model model){
|
||||||
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
|
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
|
||||||
|
@ -2,7 +2,7 @@ package com.codesdream.ase.controller;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.codesdream.ase.component.datamanager.JSONParameter;
|
import com.codesdream.ase.component.datamanager.JSONParameter;
|
||||||
import com.codesdream.ase.component.json.respond.FailedSONRespond;
|
import com.codesdream.ase.component.json.respond.JSONStandardFailedRespond;
|
||||||
import com.codesdream.ase.component.json.respond.JSONBaseRespondObject;
|
import com.codesdream.ase.component.json.respond.JSONBaseRespondObject;
|
||||||
import com.codesdream.ase.component.permission.ASEUsernameEncoder;
|
import com.codesdream.ase.component.permission.ASEUsernameEncoder;
|
||||||
import com.codesdream.ase.component.json.request.UserLoginChecker;
|
import com.codesdream.ase.component.json.request.UserLoginChecker;
|
||||||
@ -41,20 +41,21 @@ public class LoginController {
|
|||||||
return "login";
|
return "login";
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/login/check", method = RequestMethod.POST)
|
@RequestMapping(value = "/login/check_exists", method = RequestMethod.POST)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
String checkLogin(HttpServletRequest request){
|
String checkExists(HttpServletRequest request){
|
||||||
|
|
||||||
// 检查是否为JSON
|
// 检查是否为JSON
|
||||||
Optional<JSONObject> json = jsonParameter.getJSONByRequest(request);
|
Optional<JSONObject> json = jsonParameter.getJSONByRequest(request);
|
||||||
if(!json.isPresent()) return jsonParameter.getJSONString(new FailedSONRespond());
|
if(!json.isPresent()) return jsonParameter.getJSONString(new JSONStandardFailedRespond());
|
||||||
|
|
||||||
|
|
||||||
UserLoginChecker loginChecker = json.get().toJavaObject(UserLoginChecker.class);
|
UserLoginChecker loginChecker = json.get().toJavaObject(UserLoginChecker.class);
|
||||||
// 检查类型
|
|
||||||
|
// 检查学号对应的用户名是否存在
|
||||||
if(loginChecker.getCheckType().equals("UsernameExistChecker")){
|
if(loginChecker.getCheckType().equals("UsernameExistChecker")){
|
||||||
// 根据学号计算用户名
|
// 根据学号计算用户名
|
||||||
String user = usernameEncoder.encode(loginChecker.getUsername()) ;
|
String user = userService.getUsernameByStudentId(loginChecker.getUsername());
|
||||||
// 查询用户名存在状态
|
// 查询用户名存在状态
|
||||||
boolean existStatus = userService.checkIfUserExists(user).getKey();
|
boolean existStatus = userService.checkIfUserExists(user).getKey();
|
||||||
// 构造返回对象
|
// 构造返回对象
|
||||||
@ -64,8 +65,33 @@ public class LoginController {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 返回失败对象
|
// 返回失败对象
|
||||||
return jsonParameter.getJSONString(new JSONBaseRespondObject());
|
return jsonParameter.getJSONString(new JSONStandardFailedRespond());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据学号计算对应的username
|
||||||
|
@RequestMapping(value = "/login/check_uid", method = RequestMethod.POST)
|
||||||
|
@ResponseBody
|
||||||
|
String checkUsernameByStudentID(HttpServletRequest request){
|
||||||
|
// 检查是否为JSON
|
||||||
|
Optional<JSONObject> json = jsonParameter.getJSONByRequest(request);
|
||||||
|
if(!json.isPresent()) return jsonParameter.getJSONString(new JSONStandardFailedRespond());
|
||||||
|
|
||||||
|
UserLoginChecker loginChecker = json.get().toJavaObject(UserLoginChecker.class);
|
||||||
|
|
||||||
|
if(loginChecker.getCheckType().equals("UIDGeneratorChecker")) {
|
||||||
|
UserLoginCheckerJSONRespond respond = new UserLoginCheckerJSONRespond();
|
||||||
|
respond.setRespondInformation(userService.getUsernameByStudentId(loginChecker.getUsername()));
|
||||||
|
return jsonParameter.getJSONString(respond);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 返回失败对象
|
||||||
|
return jsonParameter.getJSONString(new JSONStandardFailedRespond());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.codesdream.ase.exception;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
|
||||||
|
public class JSONTokenExpiredException extends AuthenticationException {
|
||||||
|
public JSONTokenExpiredException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.codesdream.ase.exception;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
|
||||||
|
public class JSONTokenIncorrectSignedException extends AuthenticationException {
|
||||||
|
|
||||||
|
public JSONTokenIncorrectSignedException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
31
src/main/java/com/codesdream/ase/model/auth/JSONToken.java
Normal file
31
src/main/java/com/codesdream/ase/model/auth/JSONToken.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package com.codesdream.ase.model.auth;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
// token记录
|
||||||
|
@Data
|
||||||
|
@Entity
|
||||||
|
@Table(name = "json_tokens")
|
||||||
|
public class JSONToken {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
// token对应的用户
|
||||||
|
@Column(unique = true)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
// token值
|
||||||
|
@Column(unique = true)
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
// 客户端标识口令
|
||||||
|
private String clientCode;
|
||||||
|
|
||||||
|
// token过期时间
|
||||||
|
private Date expiredDate;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.codesdream.ase.repository.auth;
|
||||||
|
|
||||||
|
import com.codesdream.ase.model.auth.JSONToken;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface JSONTokenRepository extends CrudRepository<JSONToken, Integer> {
|
||||||
|
Optional<JSONToken> findByUsername(String username);
|
||||||
|
}
|
63
src/main/java/com/codesdream/ase/service/AuthService.java
Normal file
63
src/main/java/com/codesdream/ase/service/AuthService.java
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package com.codesdream.ase.service;
|
||||||
|
|
||||||
|
import com.codesdream.ase.component.auth.AuthTokenGenerator;
|
||||||
|
import com.codesdream.ase.model.auth.JSONToken;
|
||||||
|
import com.codesdream.ase.model.permission.User;
|
||||||
|
import com.codesdream.ase.repository.auth.JSONTokenRepository;
|
||||||
|
import com.sun.org.apache.xpath.internal.operations.Bool;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
// 认证服务
|
||||||
|
@Service
|
||||||
|
public class AuthService implements IAuthService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JSONTokenRepository jsonTokenRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IUserService userService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AuthTokenGenerator authTokenGenerator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<JSONToken> findTokenByUserName(String username) {
|
||||||
|
return jsonTokenRepository.findByUsername(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTokenIfExpired(JSONToken token) {
|
||||||
|
return token.getExpiredDate().compareTo(new Date()) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> userNewTokenGetter(String username, String clientCode) {
|
||||||
|
Pair<Boolean, User> userPair = userService.checkIfUserExists(username);
|
||||||
|
if(userPair.getKey()){
|
||||||
|
Optional<JSONToken> jsonTokenOptional = jsonTokenRepository.findByUsername(username);
|
||||||
|
JSONToken token = jsonTokenOptional.orElseGet(JSONToken::new);
|
||||||
|
|
||||||
|
// 过期时间设置为三十分钟后
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
currentTime +=30*60*1000;
|
||||||
|
token.setExpiredDate(new Date(currentTime));
|
||||||
|
token.setToken(authTokenGenerator.generateAuthToken(username));
|
||||||
|
|
||||||
|
|
||||||
|
// 设置用户名
|
||||||
|
token.setUsername(username);
|
||||||
|
// 设置客户端代号
|
||||||
|
token.setClientCode(clientCode);
|
||||||
|
|
||||||
|
// 在数据库中更新新的token
|
||||||
|
token = jsonTokenRepository.save(token);
|
||||||
|
return Optional.ofNullable(token.getToken());
|
||||||
|
}
|
||||||
|
else return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
16
src/main/java/com/codesdream/ase/service/IAuthService.java
Normal file
16
src/main/java/com/codesdream/ase/service/IAuthService.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package com.codesdream.ase.service;
|
||||||
|
|
||||||
|
import com.codesdream.ase.model.auth.JSONToken;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface IAuthService {
|
||||||
|
// 通过用户名查找与对应用户相关联的token
|
||||||
|
Optional<JSONToken> findTokenByUserName(String username);
|
||||||
|
|
||||||
|
// 检查token是否过期
|
||||||
|
boolean checkTokenIfExpired(JSONToken token);
|
||||||
|
|
||||||
|
// 为用户获得一个新的API Token
|
||||||
|
Optional<String> userNewTokenGetter(String username, String clientCode);
|
||||||
|
}
|
@ -24,6 +24,7 @@ public interface IUserService {
|
|||||||
|
|
||||||
User findUserByUsername(String username);
|
User findUserByUsername(String username);
|
||||||
|
|
||||||
|
// 查询用户是否存在
|
||||||
public Pair<Boolean, User> checkIfUserExists(String username);
|
public Pair<Boolean, User> checkIfUserExists(String username);
|
||||||
|
|
||||||
// 获得用户所有的权限角色
|
// 获得用户所有的权限角色
|
||||||
@ -38,6 +39,9 @@ public interface IUserService {
|
|||||||
// 根据学号生成随机用户名
|
// 根据学号生成随机用户名
|
||||||
void generateRandomUsernameByStudentID(User user, String id);
|
void generateRandomUsernameByStudentID(User user, String id);
|
||||||
|
|
||||||
|
// 更具学号获得对应的用户名
|
||||||
|
String getUsernameByStudentId(String studentId);
|
||||||
|
|
||||||
// 随机生成一个用户名
|
// 随机生成一个用户名
|
||||||
void generateRandomUsername(User user);
|
void generateRandomUsername(User user);
|
||||||
|
|
||||||
|
@ -81,6 +81,11 @@ public class UserService implements IUserService {
|
|||||||
user.setUsername(usernameEncoder.encode(id));
|
user.setUsername(usernameEncoder.encode(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsernameByStudentId(String studentId) {
|
||||||
|
return usernameEncoder.encode(studentId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateRandomUsername(User user) {
|
public void generateRandomUsername(User user) {
|
||||||
user.setUsername(usernameEncoder.encode(UUID.randomUUID().toString()));
|
user.setUsername(usernameEncoder.encode(UUID.randomUUID().toString()));
|
||||||
|
Loading…
Reference in New Issue
Block a user