调整认证服务的API接口格式;加入客户端代号, 取消dataSHA1;调整Spring Security;

This commit is contained in:
Saturneric 2020-03-16 12:41:15 +08:00
parent 2da6f6f8f8
commit 80e46c8cb8
21 changed files with 250 additions and 135 deletions

View File

@ -6,13 +6,14 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Date; import java.util.Date;
// 随机特征码生成器
@Component @Component
public class JSONRandomCodeGenerator { public class JSONRandomCodeGenerator {
@Resource @Resource
private SHA1Encoder encoder; private SHA1Encoder encoder;
public String generateRandomCode(String username, Date date, String apiSHA1){ public String generateRandomCode(String username, Date date, String clientCode){
return encoder.encode(String.format("RandomCode [%s][%s][%s]", return encoder.encode(String.format("RandomCode [%s][%s][%s]",
username, date.toString(), apiSHA1)); username, date.toString(), clientCode));
} }
} }

View File

@ -7,14 +7,15 @@ import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection; import java.util.Collection;
// 关联Token与其他用户的相关数据的认证对象 // 关联Token与其他用户的相关数据的授权柄
public class JSONTokenAuthenticationToken extends AbstractAuthenticationToken { public class JSONTokenAuthenticationToken extends AbstractAuthenticationToken {
// token 产生的签名 // 客户端签名
String signed = null; private String signed = null;
// 用户名 // 用户名
Object principal = null; private Object principal = null;
// JSON 特征随机代码 // 客户端代码
String randomCode = null; private String clientCode = null;
/** /**
* Creates a token with the supplied array of authorities. * Creates a token with the supplied array of authorities.
@ -22,18 +23,21 @@ public class JSONTokenAuthenticationToken extends AbstractAuthenticationToken {
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the principal * @param authorities the collection of <tt>GrantedAuthority</tt>s for the principal
* represented by this authentication object. * represented by this authentication object.
*/ */
public JSONTokenAuthenticationToken(UserDetails principal, String signed, Collection<? extends GrantedAuthority> authorities) { public JSONTokenAuthenticationToken(UserDetails principal,
String clientCode,
Collection<? extends GrantedAuthority> authorities)
{
super(authorities); super(authorities);
this.principal = principal; this.principal = principal;
this.randomCode = null; this.clientCode = clientCode;
this.signed = signed; this.signed = null;
setAuthenticated(true); setAuthenticated(true);
} }
public JSONTokenAuthenticationToken(String principal, String randomCode, String signed) { public JSONTokenAuthenticationToken(String principal, String clientCode, String signed) {
super(null); super(null);
this.principal = principal; this.principal = principal;
this.randomCode = randomCode; this.clientCode = clientCode;
this.signed = signed; this.signed = signed;
setAuthenticated(false); setAuthenticated(false);
} }
@ -48,11 +52,11 @@ public class JSONTokenAuthenticationToken extends AbstractAuthenticationToken {
return principal; return principal;
} }
public String getRandomCode() { public String getClientCode() {
return randomCode; return clientCode;
} }
public void setRandomCode(String randomCode) { public void setClientCode(String clientCode) {
this.randomCode = randomCode; this.clientCode = clientCode;
} }
} }

View File

@ -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;
}
}

View File

@ -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;
@ -56,6 +58,38 @@ 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对象获得对应的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);
@ -67,4 +101,6 @@ public class JSONParameter {
return json.map(jsonObject -> getJavaObject(jsonObject, type)); return json.map(jsonObject -> getJavaObject(jsonObject, type));
} }
} }

View File

@ -8,9 +8,6 @@ public class UserLoginChecker {
private String checkType; private String checkType;
private String username; private String username;
private String password; private String password;
private String clientCode;
// // 客户端类型
// private String clientType;
// // JSON签名
// private String signed;
} }

View File

@ -0,0 +1,5 @@
package com.codesdream.ase.component.json.respond;
public class EmptyDataObjectRespond {
}

View File

@ -1,9 +0,0 @@
package com.codesdream.ase.component.json.respond;
// 请求失败返回JSON
public class FailedSONRespond extends JSONBaseRespondObject {
public FailedSONRespond(){
super();
this.status = "fail";
}
}

View File

@ -2,20 +2,57 @@ package com.codesdream.ase.component.json.respond;
import com.codesdream.ase.component.json.JSONBaseObject; 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 extends JSONBaseObject { public class JSONBaseRespondObject extends JSONBaseObject {
// 请求成功状态
String status = "fail";
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;
} }
} }

View File

@ -0,0 +1,8 @@
package com.codesdream.ase.component.json.respond;
// 请求失败返回JSON
public class JSONStandardFailedRespond extends JSONBaseRespondObject {
public JSONStandardFailedRespond(){
super(500, "failed");
}
}

View File

@ -3,17 +3,12 @@ package com.codesdream.ase.component.json.respond;
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 = false;
boolean loginStatus = false; boolean loginStatus = false;
boolean userBanned = false; boolean userBanned = false;
String respondInformation = ""; String respondInformation = "";
String token = ""; String token = "";
public UserLoginCheckerJSONRespond(){
super("success");
}
} }

View File

@ -1,6 +1,6 @@
package com.codesdream.ase.component.json.respond; package com.codesdream.ase.component.json.respond;
// 返回登录后的授权码(用于客户端生成签名) // 返回登录后的授权码(用于客户端生成签名)
public class UserLoginTokenJSONRespond extends JSONBaseRespondObject { public class UserLoginTokenJSONRespond {
String token; String token;
} }

View File

@ -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!"); // 对匿名用户返回403
response.getWriter().print(jsonParameter.getJSONStandardRespond403());
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));
} }
} }

View File

@ -33,6 +33,6 @@ public class ASEAuthenticationFailureHandler extends SimpleUrlAuthenticationFail
respond.setRespondInformation("Authentication Failed"); respond.setRespondInformation("Authentication Failed");
// 填充response对象 // 填充response对象
response.getWriter().write(jsonParameter.getJSONString(respond)); response.getWriter().write(jsonParameter.getJSONStandardRespond200(respond));
} }
} }

View File

@ -1,5 +1,6 @@
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;
@ -35,31 +36,26 @@ public class ASEAuthenticationSuccessHandler extends SavedRequestAwareAuthentica
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);
}
*/
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");
// 获得 JSONTokenAuthenticationToken
JSONTokenAuthenticationToken authenticationToken = (JSONTokenAuthenticationToken) authentication;
User user = (User) authenticationToken.getPrincipal();
Optional<String> tokenOptional = authService.userNewTokenGetter(
user.getUsername(), authenticationToken.getClientCode());
// 获得session id
/*WebAuthenticationDetails webAuthenticationDetails = (WebAuthenticationDetails) (authentication.getDetails());*/
User user = (User) authentication.getPrincipal();
// 获得api token
Optional<String> tokenOptional = authService.userNewTokenGetter(user.getUsername());
if(tokenOptional.isPresent()){ if(tokenOptional.isPresent()){
respond.setToken(tokenOptional.get()); respond.setToken(tokenOptional.get());
} }
else respond.setToken(""); else respond.setToken("");
response.getWriter().write(jsonParameter.getJSONString(respond)); response.getWriter().write(jsonParameter.getJSONStandardRespond200(respond));
} }
} }

View File

@ -1,29 +1,18 @@
package com.codesdream.ase.component.permission; package com.codesdream.ase.component.permission;
import com.alibaba.fastjson.JSONObject;
import com.codesdream.ase.component.auth.AJAXRequestChecker; import com.codesdream.ase.component.auth.AJAXRequestChecker;
import com.codesdream.ase.component.auth.JSONRandomCodeGenerator; import com.codesdream.ase.component.auth.JSONRandomCodeGenerator;
import com.codesdream.ase.component.auth.JSONSignedGenerator; import com.codesdream.ase.component.auth.JSONSignedGenerator;
import com.codesdream.ase.component.auth.JSONTokenAuthenticationToken; 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.exception.JSONTokenExpiredException;
import com.codesdream.ase.exception.JSONTokenIncorrectSignedException;
import com.codesdream.ase.model.auth.JSONToken; import com.codesdream.ase.model.auth.JSONToken;
import com.codesdream.ase.service.AuthService; import com.codesdream.ase.service.AuthService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -32,7 +21,6 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.nio.file.attribute.UserPrincipalNotFoundException;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.Optional; import java.util.Optional;
@ -64,56 +52,68 @@ public class ASEJSONTokenAuthenticationFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { throws ServletException, IOException {
// 用户名
String username = request.getHeader( "username"); String username = request.getHeader( "username");
// 客户端签名
String signed = request.getHeader("signed"); String signed = request.getHeader("signed");
String rawDate = request.getHeader("date"); // 时间戳
String timestamp = request.getHeader("timestamp");
// 对API的内容取哈希码 if (signed != null && username != null && timestamp != null) {
String apiSHA1 = request.getHeader("apiSHA1");
if (signed != null && username != null && rawDate != null && apiSHA1 != null) {
// 获得具体时间 // 获得具体时间
Date date = new Date(Long.parseLong(rawDate)); Date date = new Date(Long.parseLong(timestamp));
// 检查时间是否合理 Date now = new Date();
// ...
// 生成特征随机代码 // 限制时间戳有效区间为60s
String randomCode = randomCodeGenerator.generateRandomCode(username, date, apiSHA1); long dtTime = 60*1000;
Date maxDate = new Date(now.getTime() + dtTime);
// 进行验证 // 检查时间戳是否合理
Optional<JSONToken> optionalJSONToken = authService.findTokenByUserName(username); if(maxDate.after(date)) {
if(!optionalJSONToken.isPresent()){ // 从服务器中查找token
throw new UserPrincipalNotFoundException("Token Not Found"); Optional<JSONToken> optionalJSONToken = authService.findTokenByUserName(username);
} if (optionalJSONToken.isPresent()) {
JSONToken token = optionalJSONToken.get();
// 检查token是否过期 // 检查token是否过期
JSONToken token = optionalJSONToken.get(); if (!authService.checkTokenIfExpired(token)) {
if(!authService.checkTokenIfExpired(token)) { // 生成特征随机代码
String randomCode = randomCodeGenerator.generateRandomCode(username, date, token.getClientCode());
log.info(String.format("Determined Signed: %s", log.info(String.format("Determined Signed: %s",
signedGenerator.generateSigned(username, randomCode, token.getToken()))); signedGenerator.generateSigned(username, randomCode, token.getToken())));
// 检查签名是否正确 // 检查签名是否正确
if (signed.equals(signedGenerator.generateSigned(username, randomCode, token.getToken()))) { if (signed.equals(signedGenerator.generateSigned(username, randomCode, token.getToken()))) {
// 执行授权操作
// 查询用户的相关信息 doAuthentication(username, request);
UserDetails user = userDetailsService.loadUserByUsername(username); }
}
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
// 生成认证柄 (储存上下文信息)
JSONTokenAuthenticationToken authentication = new JSONTokenAuthenticationToken(user, signed, authorities);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} }
} }
} }
filterChain.doFilter(request, response); 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);
}
} }

View File

@ -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;
@ -29,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);
@ -58,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 aClass.equals(UsernamePasswordAuthenticationToken.class); return aClass.equals(JSONTokenUsernamePasswordAuthenticationToken.class);
} }
} }

View File

@ -1,6 +1,7 @@
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.AJAXRequestChecker;
import com.codesdream.ase.component.auth.JSONTokenUsernamePasswordAuthenticationToken;
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;
@ -10,6 +11,7 @@ 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 javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -32,19 +34,19 @@ public class ASEUsernamePasswordAuthenticationFilter extends UsernamePasswordAut
// 判断是否为AJAX请求格式的数据 // 判断是否为AJAX请求格式的数据
if(!ajaxRequestChecker.checkAjaxPOSTRequest(request)) { if(!ajaxRequestChecker.checkAjaxPOSTRequest(request)) {
log.info("NOT AJAX POST Request.");
throw new AuthenticationServiceException("Authentication method not supported: NOT Ajax Method."); throw new AuthenticationServiceException("Authentication method not supported: NOT Ajax Method.");
} }
Optional<UserLoginChecker> checker = jsonParameter.getJavaObjectByRequest(request, UserLoginChecker.class); Optional<UserLoginChecker> checker = jsonParameter.getJavaObjectByRequest(request, UserLoginChecker.class);
if(!checker.isPresent()) throw new BadCredentialsException("Invalid AJAX JSON Request"); if(!checker.isPresent()) throw new BadCredentialsException("Invalid AJAX JSON Request");
log.info("JSON Object 2 Java Object Success.");
if (!checker.get().getCheckType().equals("UsernamePasswordChecker")) if (!checker.get().getCheckType().equals("UsernamePasswordChecker"))
throw new AuthenticationServiceException("Authentication not supported: NOT Username Password Type."); throw new AuthenticationServiceException("Authentication not supported: NOT Username Password Type.");
// 获得相应的用户名密码 // 获得相应的用户名密码
String username = checker.get().getUsername(); String username = checker.get().getUsername();
String password = checker.get().getPassword(); String password = checker.get().getPassword();
String clientCode = checker.get().getClientCode();
if (username == null) username = ""; if (username == null) username = "";
if (password == null) password = ""; if (password == null) password = "";
@ -53,15 +55,12 @@ public class ASEUsernamePasswordAuthenticationFilter extends UsernamePasswordAut
username = username.trim(); username = username.trim();
password = password.trim(); password = password.trim();
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(username, password);
JSONTokenUsernamePasswordAuthenticationToken authRequest =
new JSONTokenUsernamePasswordAuthenticationToken(username, password, clientCode);
log.info(String.format("User AJAX JSON Authentication: %s %s.", username, password)); authRequest.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest); return this.getAuthenticationManager().authenticate(authRequest);
} }
} }

View File

@ -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;
@ -17,7 +17,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.Optional; import java.util.Optional;
@ -48,7 +47,7 @@ public class LoginController {
// 检查是否为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);
@ -66,7 +65,7 @@ public class LoginController {
} }
else { else {
// 返回失败对象 // 返回失败对象
return jsonParameter.getJSONString(new JSONBaseRespondObject()); return jsonParameter.getJSONString(new JSONStandardFailedRespond());
} }
} }
@ -76,7 +75,7 @@ public class LoginController {
String checkUsernameByStudentID(HttpServletRequest request){ String checkUsernameByStudentID(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);
@ -87,7 +86,7 @@ public class LoginController {
} }
else { else {
// 返回失败对象 // 返回失败对象
return jsonParameter.getJSONString(new JSONBaseRespondObject()); return jsonParameter.getJSONString(new JSONStandardFailedRespond());
} }

View File

@ -23,6 +23,9 @@ public class JSONToken {
@Column(unique = true) @Column(unique = true)
private String token; private String token;
// 客户端标识口令
private String clientCode;
// token过期时间 // token过期时间
private Date expiredDate; private Date expiredDate;
} }

View File

@ -36,18 +36,24 @@ public class AuthService implements IAuthService {
} }
@Override @Override
public Optional<String> userNewTokenGetter(String username) { public Optional<String> userNewTokenGetter(String username, String clientCode) {
Pair<Boolean, User> userPair = userService.checkIfUserExists(username); Pair<Boolean, User> userPair = userService.checkIfUserExists(username);
if(userPair.getKey()){ if(userPair.getKey()){
Optional<JSONToken> jsonTokenOptional = jsonTokenRepository.findByUsername(username); Optional<JSONToken> jsonTokenOptional = jsonTokenRepository.findByUsername(username);
JSONToken token = jsonTokenOptional.orElseGet(JSONToken::new); JSONToken token = jsonTokenOptional.orElseGet(JSONToken::new);
// 过期时间设置为三十分钟后 // 过期时间设置为三十分钟后
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
currentTime +=30*60*1000; currentTime +=30*60*1000;
token.setExpiredDate(new Date(currentTime)); token.setExpiredDate(new Date(currentTime));
token.setToken(authTokenGenerator.generateAuthToken(username)); token.setToken(authTokenGenerator.generateAuthToken(username));
// 设置用户名 // 设置用户名
token.setUsername(username); token.setUsername(username);
// 设置客户端代号
token.setClientCode(clientCode);
// 在数据库中更新新的token // 在数据库中更新新的token
token = jsonTokenRepository.save(token); token = jsonTokenRepository.save(token);
return Optional.ofNullable(token.getToken()); return Optional.ofNullable(token.getToken());

View File

@ -12,5 +12,5 @@ public interface IAuthService {
boolean checkTokenIfExpired(JSONToken token); boolean checkTokenIfExpired(JSONToken token);
// 为用户获得一个新的API Token // 为用户获得一个新的API Token
Optional<String> userNewTokenGetter(String username); Optional<String> userNewTokenGetter(String username, String clientCode);
} }