-
Notifications
You must be signed in to change notification settings - Fork 701
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#398 authentication support (用户注册不在scope)
- Loading branch information
Showing
15 changed files
with
692 additions
and
45 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
...api/src/main/java/com/vip/saturn/job/console/controller/gui/AuthenticationController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.vip.saturn.job.console.controller.gui; | ||
|
||
import com.vip.saturn.job.console.controller.SuccessResponseEntity; | ||
import com.vip.saturn.job.console.domain.RequestResult; | ||
import com.vip.saturn.job.console.exception.SaturnJobConsoleException; | ||
import com.vip.saturn.job.console.mybatis.entity.User; | ||
import com.vip.saturn.job.console.service.AuthenticationService; | ||
import com.vip.saturn.job.console.utils.SaturnConsoleUtils; | ||
import com.vip.saturn.job.console.utils.SessionAttributeKeys; | ||
import io.swagger.annotations.ApiResponse; | ||
import io.swagger.annotations.ApiResponses; | ||
import org.slf4j.Logger; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestMethod; | ||
|
||
import javax.annotation.Resource; | ||
import javax.servlet.http.HttpServletRequest; | ||
import java.io.IOException; | ||
|
||
@RequestMapping("/console/authentication") | ||
public class AuthenticationController extends AbstractGUIController { | ||
|
||
private static final Logger AUDIT_LOGGER = SaturnConsoleUtils.getAuditLogger(); | ||
|
||
@Resource | ||
private AuthenticationService authenticationService; | ||
|
||
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)}) | ||
@RequestMapping(value = "/login", method = {RequestMethod.POST}) | ||
public SuccessResponseEntity login(String username, String password, HttpServletRequest request) throws IOException, SaturnJobConsoleException { | ||
|
||
User user = authenticationService.authenticate(username, password); | ||
if (user == null) { | ||
throw new SaturnJobConsoleException("Invalid username or password"); | ||
} | ||
|
||
request.getSession().setAttribute(SessionAttributeKeys.LOGIN_USER_REAL_NAME, user.getRealName()); | ||
|
||
AUDIT_LOGGER.info("{}({}) was login where ip={} ", user.getUserName(), user.getRealName(), request.getRemoteAddr()); | ||
|
||
return new SuccessResponseEntity(); | ||
} | ||
|
||
@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)}) | ||
@RequestMapping(value = "/logout", method = {RequestMethod.GET, RequestMethod.POST}) | ||
public SuccessResponseEntity logout(HttpServletRequest request) { | ||
AUDIT_LOGGER.info("{}({}) logout, ip {}. ", getCurrentLoginUserName(), getCurrentLoginUserRealName(), request.getRemoteAddr()); | ||
request.getSession().invalidate(); | ||
return new SuccessResponseEntity(); | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
saturn-console-api/src/main/java/com/vip/saturn/job/console/filter/AuthenticationFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.vip.saturn.job.console.filter; | ||
|
||
import com.alibaba.fastjson.JSON; | ||
import com.vip.saturn.job.console.domain.RequestResultHelper; | ||
import com.vip.saturn.job.console.utils.SessionAttributeKeys; | ||
|
||
import javax.servlet.*; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
import java.io.IOException; | ||
import java.io.PrintWriter; | ||
|
||
public class AuthenticationFilter implements Filter { | ||
|
||
@Override | ||
public void init(FilterConfig filterConfig) throws ServletException { | ||
} | ||
|
||
@Override | ||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { | ||
HttpServletRequest req = (HttpServletRequest) request; | ||
HttpServletResponse resp = (HttpServletResponse) response; | ||
|
||
if (req.getSession().getAttribute(SessionAttributeKeys.LOGIN_USER_NAME) == null) { | ||
response.setContentType("application/json;charset=UTF-8"); | ||
PrintWriter writer = resp.getWriter(); | ||
writer.print(JSON.toJSONString(RequestResultHelper.redirect("/login"))); | ||
writer.flush(); | ||
return; | ||
} | ||
|
||
chain.doFilter(request, response); | ||
} | ||
|
||
@Override | ||
public void destroy() { | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
...n-console-api/src/main/java/com/vip/saturn/job/console/service/AuthenticationService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.vip.saturn.job.console.service; | ||
|
||
import com.vip.saturn.job.console.exception.SaturnJobConsoleException; | ||
import com.vip.saturn.job.console.mybatis.entity.User; | ||
|
||
public interface AuthenticationService { | ||
|
||
User authenticate(String username, String password) throws SaturnJobConsoleException; | ||
|
||
} |
41 changes: 41 additions & 0 deletions
41
...-api/src/main/java/com/vip/saturn/job/console/service/impl/AuthenticationServiceImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.vip.saturn.job.console.service.impl; | ||
|
||
import com.vip.saturn.job.console.exception.SaturnJobConsoleException; | ||
import com.vip.saturn.job.console.mybatis.entity.User; | ||
import com.vip.saturn.job.console.mybatis.repository.UserRepository; | ||
import com.vip.saturn.job.console.service.AuthenticationService; | ||
import com.vip.saturn.job.console.utils.PasswordUtils; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.util.StringUtils; | ||
|
||
public class AuthenticationServiceImpl implements AuthenticationService { | ||
|
||
@Autowired | ||
private UserRepository userRepository; | ||
|
||
@Value("${authentication.hash:plaintext}") | ||
private String hashMethod; | ||
|
||
@Override | ||
public User authenticate(String username, String password) throws SaturnJobConsoleException { | ||
if (StringUtils.isEmpty(password)) { | ||
return null; | ||
} | ||
|
||
User user = userRepository.select(username); | ||
if (user == null) { | ||
return null; | ||
} | ||
|
||
try { | ||
return PasswordUtils.validate(password, user.getPassword(), hashMethod) ? user : null; | ||
} catch (Exception e) { | ||
throw new SaturnJobConsoleException(e); | ||
} | ||
} | ||
|
||
public void setHashMethod(String hashMethod) { | ||
this.hashMethod = hashMethod; | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
saturn-console-api/src/main/java/com/vip/saturn/job/console/utils/PasswordUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.vip.saturn.job.console.utils; | ||
|
||
import org.apache.commons.codec.binary.Base64; | ||
|
||
import javax.crypto.SecretKey; | ||
import javax.crypto.SecretKeyFactory; | ||
import javax.crypto.spec.PBEKeySpec; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.SecureRandom; | ||
import java.security.spec.InvalidKeySpecException; | ||
|
||
public class PasswordUtils { | ||
|
||
public static final String HASH_METHOD_PLANTEXT = "plaintext"; | ||
|
||
public static final String HASH_METHOD_PBKDF2 = "PBKDF2WithHmacSHA1"; | ||
|
||
private static final int ITERATIONS = 10 * 1000; | ||
|
||
private static final int SALT_LEN = 8; | ||
|
||
private static final int KEY_LEN = 256; | ||
|
||
/** | ||
* 生成带盐的密码串,密码和盐使用'$'符号分隔。 | ||
* @param hashMethod 为JDK SecretKeyFactory支持的算法,如果算法不存在,会使用PBKDF2WithHmacSHA1 | ||
*/ | ||
public static String genPassword(String password, String hashMethod) throws Exception { | ||
byte[] salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(SALT_LEN); | ||
return hash(password, salt, hashMethod); | ||
} | ||
|
||
public static String genPassword(String password, byte[] salt, String hashMethod) throws Exception { | ||
return hash(password, salt, hashMethod) + "$" + Base64.encodeBase64String(salt); | ||
} | ||
|
||
public static String hash(String password, byte[] salt, String hashMethod) throws NoSuchAlgorithmException, InvalidKeySpecException { | ||
SecretKeyFactory secretKeyFactory; | ||
try { | ||
secretKeyFactory = SecretKeyFactory.getInstance(hashMethod); | ||
} catch (NoSuchAlgorithmException e) { | ||
secretKeyFactory = SecretKeyFactory.getInstance(HASH_METHOD_PBKDF2); | ||
} | ||
|
||
SecretKey key = secretKeyFactory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_LEN)); | ||
return Base64.encodeBase64String(key.getEncoded()); | ||
} | ||
|
||
public static boolean validate(String password, String passwordInDB, String hashMethod) throws Exception { | ||
if (PasswordUtils.HASH_METHOD_PLANTEXT.equals(hashMethod)) { | ||
return password.equals(passwordInDB); | ||
} | ||
|
||
String[] saltAndPassword = passwordInDB.split("\\$"); | ||
if (saltAndPassword.length != 2) { | ||
throw new IllegalArgumentException("Invalid password stored in DB"); | ||
} | ||
|
||
String hashOfRequestPassword = hash(password, Base64.decodeBase64(saltAndPassword[1]), hashMethod); | ||
return hashOfRequestPassword.equals(new String(saltAndPassword[0])); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
.../src/test/java/com/vip/saturn/job/console/service/impl/AuthenticationServiceImplTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.vip.saturn.job.console.service.impl; | ||
|
||
import com.vip.saturn.job.console.exception.SaturnJobConsoleException; | ||
import com.vip.saturn.job.console.mybatis.entity.User; | ||
import com.vip.saturn.job.console.mybatis.repository.UserRepository; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.runners.MockitoJUnitRunner; | ||
|
||
import static org.junit.Assert.*; | ||
import static org.mockito.Mockito.when; | ||
|
||
@RunWith(MockitoJUnitRunner.class) | ||
public class AuthenticationServiceImplTest { | ||
|
||
@Mock | ||
private UserRepository userRepository; | ||
|
||
@InjectMocks | ||
private AuthenticationServiceImpl authnService; | ||
|
||
@Test | ||
public void testAuthenticateSuccessfully() throws SaturnJobConsoleException { | ||
authnService.setHashMethod("plaintext"); | ||
User user = createUser("jeff", "password"); | ||
when(userRepository.select("jeff")).thenReturn(user); | ||
|
||
assertEquals(user, authnService.authenticate("jeff", "password")); | ||
} | ||
|
||
@Test | ||
public void testAuthenticationFailWhenUserIsNotFound() throws SaturnJobConsoleException { | ||
authnService.setHashMethod("plaintext"); | ||
when(userRepository.select("john")).thenReturn(null); | ||
|
||
assertNull(authnService.authenticate("john", "password")); | ||
} | ||
|
||
@Test | ||
public void testAuthenticationFailWhenPasswordInputIsEmpty() throws SaturnJobConsoleException { | ||
authnService.setHashMethod("plaintext"); | ||
assertNull(authnService.authenticate("john", "")); | ||
} | ||
|
||
private User createUser(String username, String password) { | ||
User user = new User(); | ||
user.setUserName(username); | ||
user.setPassword(password); | ||
|
||
return user; | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
saturn-console-api/src/test/java/com/vip/saturn/job/console/utils/PasswordUtilsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.vip.saturn.job.console.utils; | ||
|
||
import org.junit.Test; | ||
|
||
import java.security.NoSuchAlgorithmException; | ||
import java.security.spec.InvalidKeySpecException; | ||
|
||
import static org.junit.Assert.*; | ||
|
||
public class PasswordUtilsTest { | ||
|
||
@Test | ||
public void testGenSaltedPassword() throws Exception { | ||
String password = PasswordUtils.genPassword("password", "salt".getBytes(), "PBKDF2WithHmacSHA1"); | ||
assertEquals("osJkYYaChHS3VFkaVHwY8TLYjXRMFSZVpHAWGhoFITU=$c2FsdA==", password); | ||
} | ||
|
||
@Test | ||
public void testValidate() throws Exception { | ||
assertTrue(PasswordUtils.validate("password", "osJkYYaChHS3VFkaVHwY8TLYjXRMFSZVpHAWGhoFITU=$c2FsdA==", "PBKDF2WithHmacSHA1")); | ||
assertFalse(PasswordUtils.validate("password1", "osJkYYaChHS3VFkaVHwY8TLYjXRMFSZVpHAWGhoFITU=$c2FsdA==", "PBKDF2WithHmacSHA1")); | ||
assertTrue(PasswordUtils.validate("password", "password", "plaintext")); | ||
assertFalse(PasswordUtils.validate("password1", "password", "plaintext")); | ||
} | ||
|
||
@Test | ||
public void testValidateWherePasswordInDBisMalfomred() { | ||
int count = 0; | ||
try { | ||
PasswordUtils.validate("password", "password", "PBKDF2WithHmacSHA1"); | ||
} catch (Exception e) { | ||
count++; | ||
assertEquals("Invalid password stored in DB", e.getMessage()); | ||
} | ||
|
||
assertEquals(1, count); | ||
} | ||
} |
30 changes: 11 additions & 19 deletions
30
saturn-console/src/main/java/com/vip/saturn/job/console/springboot/SaturnFilterRegister.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,26 @@ | ||
package com.vip.saturn.job.console.springboot; | ||
|
||
import com.vip.saturn.job.console.filter.AuthenticationFilter; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.core.Ordered; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.filter.CharacterEncodingFilter; | ||
|
||
import com.vip.saturn.job.console.filter.RecordLastVisit; | ||
|
||
@Component | ||
public class SaturnFilterRegister { | ||
|
||
@Bean | ||
public FilterRegistrationBean registerEncodingFilter() { | ||
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); | ||
encodingFilter.setEncoding("UTF-8"); | ||
encodingFilter.setForceEncoding(true); | ||
FilterRegistrationBean registration = new FilterRegistrationBean(encodingFilter); | ||
registration.addUrlPatterns("/*"); | ||
registration.setOrder(Ordered.HIGHEST_PRECEDENCE); | ||
return registration; | ||
} | ||
@Value("${authentication.enabled:false}") | ||
private boolean authenticationEnabled; | ||
|
||
@Bean | ||
public FilterRegistrationBean registerLastVisitFilter() { | ||
RecordLastVisit lastVisit = new RecordLastVisit(); | ||
FilterRegistrationBean registration = new FilterRegistrationBean(lastVisit); | ||
registration.addUrlPatterns("/*"); | ||
registration.setOrder(3); | ||
public FilterRegistrationBean registerAuthenticationFilter() { | ||
AuthenticationFilter filter = new AuthenticationFilter(); | ||
FilterRegistrationBean registration = new FilterRegistrationBean(filter); | ||
registration.setEnabled(authenticationEnabled); | ||
registration.addUrlPatterns("/console/*"); | ||
registration.setOrder(0); | ||
return registration; | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.