增强安全策略;添加预验证;修正服务端编译问题;

This commit is contained in:
Saturneric 2020-03-25 02:01:24 +08:00
parent ae21439c2e
commit 9a8459df6c
23 changed files with 338 additions and 48 deletions

12
pom.xml
View File

@ -163,6 +163,18 @@
<addResources>true</addResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<!--suppress UnresolvedMavenProperty -->
<bootclasspath>${JAVA_HOME}/jre/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -41,6 +41,7 @@ public class ASEAuthenticationSuccessHandler extends SavedRequestAwareAuthentica
UserLoginCheckerJSONRespond respond = new UserLoginCheckerJSONRespond();
respond.setUserExist(authentication.isAuthenticated());
respond.setLoginStatus(authentication.isAuthenticated());
respond.setPvc(authService.preValidationCodeGetter());
// 获得 JSONTokenAuthenticationToken
JSONTokenAuthenticationToken authenticationToken = (JSONTokenAuthenticationToken) authentication;

View File

@ -32,11 +32,11 @@ public class ASESecurityAuthenticationProvider implements AuthenticationProvider
JSONTokenUsernamePasswordAuthenticationToken authenticationToken =
(JSONTokenUsernamePasswordAuthenticationToken) authentication;
// 获得登录表单中的学号
// 获得JSON中的学号
String username = usernameEncoder.encode((CharSequence) authenticationToken.getPrincipal());
// 获得表单中的密码
String password = passwordEncoder.encode((CharSequence) authenticationToken.getCredentials());
// 获得
// 获得JSON中的加密密码
String encrypted_password = (String) authenticationToken.getCredentials();
// 获得客户端代码
String clientCode = authenticationToken.getClientCode();
// 判断用户是否存在
UserDetails userInfo = userDetailsService.loadUserByUsername(username);
@ -45,20 +45,23 @@ public class ASESecurityAuthenticationProvider implements AuthenticationProvider
throw new UsernameNotFoundException("User Not Exist");
}
String sha256_password = userInfo.getPassword();
// 判断密码是否正确
if (!userInfo.getPassword().equals(password)) {
throw new BadCredentialsException("Password IS Uncorrected");
if(!passwordEncoder.encode(String.format(
"PASS_ENCODE [%s][%s]", sha256_password, clientCode)).equals(encrypted_password)){
throw new BadCredentialsException("Password IS INCORRECT");
}
// 判断账号是否停用/删除
if (!userInfo.isEnabled()) {
throw new DisabledException("User IS Disabled");
}
else if(!userInfo.isAccountNonLocked()){
else if(!userInfo.isAccountNonLocked()) {
throw new LockedException("User IS Locked");
}
else if(!userInfo.isAccountNonExpired()){
throw new AccountExpiredException("User IS Expired");
else if(!userInfo.isAccountNonExpired()) {
throw new AccountExpiredException("User IS Expired");
}
// 生成权限列表

View File

@ -63,6 +63,7 @@ public class ASEUsernamePasswordAuthenticationFilter extends UsernamePasswordAut
// 获得相应的用户名密码
String username = checker.getUsername();
// 得到加密密码
String password = checker.getPassword();
String clientCode = checker.getClientCode();

View File

@ -15,4 +15,10 @@ public class TimestampExpiredChecker {
return timestampDate.before(maxDate);
}
public boolean checkDateBeforeMaxTime(Date date, int seconds){
long currentTime = System.currentTimeMillis();
Date maxDate = new Date(currentTime + seconds * 1000);
return date.before(maxDate);
}
}

View File

@ -76,5 +76,10 @@ public class QuickJSONRespond {
return getJSONStandardRespond(400, "Bad Request", info);
}
// 获得标准的JSON响应字符串返回(400状态)
public String getRespond409(String info){
return getJSONStandardRespond(409, "Conflict", info);
}
}

View File

@ -0,0 +1,16 @@
package com.codesdream.ase.component.json.respond;
import com.sun.org.apache.xpath.internal.operations.Bool;
import lombok.Data;
import java.util.List;
import java.util.Set;
@Data
public class PermissionJSONRespond {
private Boolean tagExist = null;
private Boolean actionSuccess = null;
private Integer tagId = null;
private String tagName = null;
private Set<Integer> users = null;
}

View File

@ -12,5 +12,6 @@ public class UserLoginCheckerJSONRespond {
String respondInformation = null;
String token = null;
String uid = null;
String pvc = null;
}

View File

@ -17,7 +17,9 @@ public class HomeController {
@RequestMapping(value = "/home")
public String showHomeView(Model model, Principal principal){
User user = userService.findUserByUsername(principal.getName());
Optional<User> userOptional = userService.findUserByUsername(principal.getName());
if(!userOptional.isPresent()) return "error";
User user = userOptional.get();
// 为视图模板指定参数
model.addAttribute("username", user.getUsername().substring(0, 18));
model.addAttribute("real_name", user.getUserDetail().getRealName());

View File

@ -6,6 +6,7 @@ import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.json.respond.JSONStandardFailedRespond;
import com.codesdream.ase.component.json.request.UserLoginChecker;
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
import com.codesdream.ase.service.IAuthService;
import com.codesdream.ase.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
@ -35,6 +36,9 @@ public class LoginController {
@Resource
private IUserService userService;
@Resource
private IAuthService authService;
@RequestMapping(value = "/login")
String printLogin(Model model) {
@ -73,12 +77,22 @@ public class LoginController {
@RequestMapping(value = "/login/check_uid", method = RequestMethod.POST)
@ResponseBody
String checkUsernameByStudentID(HttpServletRequest request){
String preValidationCode = request.getHeader("pvc");
// 检查随机预验证码
if(preValidationCode == null || !authService.preValidationCodeChecker(preValidationCode))
return quickJSONRespond.getRespond403("Invalid PreValidationCode");
// 检查是否为JSON
Optional<JSONObject> json = jsonParameter.getJSONByRequest(request);
if(!json.isPresent()) return jsonParameter.getJSONString(new JSONStandardFailedRespond());
UserLoginChecker loginChecker = json.get().toJavaObject(UserLoginChecker.class);
if(loginChecker.getUsername() == null || loginChecker.getCheckType() == null)
return quickJSONRespond.getRespond406("Request Violates The Interface Protocol");
if(loginChecker.getCheckType().equals("UIDGeneratorChecker")) {
UserLoginCheckerJSONRespond respond = new UserLoginCheckerJSONRespond();
respond.setUid(userService.getUsernameByStudentId(loginChecker.getUsername()));

View File

@ -1,23 +0,0 @@
package com.codesdream.ase.controller;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("pmt")
public class PermissionContainer {
@Secured({"ROLE_ADMIN","ROLE_USER"})
@PostMapping("tag")
public String createTag(HttpServletRequest request, Authentication authentication){
return "";
}
}

View File

@ -0,0 +1,143 @@
package com.codesdream.ase.controller;
import com.alibaba.fastjson.JSONObject;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.json.respond.PermissionJSONRespond;
import com.codesdream.ase.model.permission.Tag;
import com.codesdream.ase.model.permission.User;
import com.codesdream.ase.service.IUserService;
import com.codesdream.ase.service.PermissionService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
@RestController
@RequestMapping("pmt")
public class PermissionController {
@Resource
private PermissionService permissionService;
@Resource
private IUserService userService;
@Resource
private JSONParameter jsonParameter;
@Resource
private QuickJSONRespond jsonRespond;
// 根据名字创建新的标签
@PostMapping("tag/create")
public String createTag(HttpServletRequest request){
Optional<JSONObject> jsonObjectOptional = jsonParameter.getJSONByRequest(request);
if(!jsonObjectOptional.isPresent()) return jsonRespond.getRespond400("Illegal JSON Format");
JSONObject jsonObject = jsonObjectOptional.get();
String tagName = jsonObject.getString("name");
if(tagName == null) return jsonRespond.getRespond406("Missing Tag Name");
// 检查JSON是否合法
Optional<Tag> tagOptional = permissionService.findTag(tagName);
if(tagOptional.isPresent()) return jsonRespond.getRespond409("Tag Name Already Exist");
Tag newTag = permissionService.getDefaultTag(tagName);
newTag = permissionService.save(newTag);
PermissionJSONRespond respond = new PermissionJSONRespond();
respond.setActionSuccess(true);
respond.setTagId(newTag.getId());
respond.setTagName(newTag.getName());
return jsonRespond.getRespond200(null, respond);
}
// 根据名字搜索标签的简要信息
@PostMapping("tag/search")
public String checkTag(HttpServletRequest request){
Optional<JSONObject> jsonObjectOptional = jsonParameter.getJSONByRequest(request);
if(!jsonObjectOptional.isPresent()) return jsonRespond.getRespond400("Illegal JSON Format");
JSONObject jsonObject = jsonObjectOptional.get();
String tagName = jsonObject.getString("name");
if(tagName == null) return jsonRespond.getRespond406("Problem With Tag Name");
Optional<Tag> tagOptional = permissionService.findTag(tagName);
PermissionJSONRespond respond = new PermissionJSONRespond();
respond.setActionSuccess(true);
if(tagOptional.isPresent()){
respond.setTagExist(true);
respond.setTagId(tagOptional.get().getId());
respond.setTagName(tagOptional.get().getName());
}
else respond.setTagExist(false);
return jsonRespond.getRespond200(null, respond);
}
// 由标签ID找到用户ID列表
@PostMapping("tag/get/users")
public String getUsersTag(HttpServletRequest request){
Optional<JSONObject> jsonObjectOptional = jsonParameter.getJSONByRequest(request);
if(!jsonObjectOptional.isPresent()) return jsonRespond.getRespond400("Illegal JSON Format");
JSONObject jsonObject = jsonObjectOptional.get();
Integer tagId = jsonObject.getInteger("id");
if(tagId == null) return jsonRespond.getRespond406("Problem With Tag ID");
Optional<Tag> tagOptional = permissionService.findTag(tagId);
PermissionJSONRespond respond = new PermissionJSONRespond();
respond.setActionSuccess(true);
if(tagOptional.isPresent()){
respond.setTagExist(true);
respond.setTagId(tagOptional.get().getId());
Set<Integer> userIds = new HashSet<>();
for(User user : permissionService.getUsersFromTag(tagOptional.get())) {
userIds.add(user.getId());
}
respond.setUsers(userIds);
}
else respond.setTagExist(false);
return jsonRespond.getRespond200(null, respond);
}
// 将用户添加到Tag中
@PostMapping("tag/add/user")
public String addUserTag(HttpServletRequest request){
Optional<JSONObject> jsonObjectOptional = jsonParameter.getJSONByRequest(request);
if(!jsonObjectOptional.isPresent()) return jsonRespond.getRespond400("Illegal JSON Format");
JSONObject jsonObject = jsonObjectOptional.get();
Integer tagId = jsonObject.getInteger("tagId");
Integer userId = jsonObject.getInteger("userId");
if(userId == null || tagId == null)
return jsonRespond.getRespond406("Request Violates The Interface Protocol");
Optional<User> user = userService.findUserById(userId);
if(!user.isPresent()) return jsonRespond.getRespond406("User Not Exist");
Optional<Tag> tag = permissionService.findTag(tagId);
if(!tag.isPresent()) return jsonRespond.getRespond406("Tag Not Exist");
// 检查用户是否已经在标签中
if(tag.get().getUsers().contains(user.get())) return jsonRespond.getRespond409("User Already In The Tag");
permissionService.addUserToTag(tag.get(), user.get());
return jsonRespond.getRespond200("Add User TO Tag Successful");
}
}

View File

@ -0,0 +1,20 @@
package com.codesdream.ase.model.auth;
import lombok.Data;
import javax.persistence.*;
import java.util.Date;
@Data
@Entity
@Table(name = "pre_validation_code")
public class PreValidationCode {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String value;
private Date date = new Date();
}

View File

@ -0,0 +1,12 @@
package com.codesdream.ase.repository.auth;
import com.codesdream.ase.model.auth.PreValidationCode;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface PreValidationCodeRepository extends CrudRepository<PreValidationCode, Integer> {
Optional<PreValidationCode> findByValue(String value);
}

View File

@ -11,6 +11,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.Optional;
@Service
public class ASEUserDetailsService implements UserDetailsService {
@ -25,7 +26,9 @@ public class ASEUserDetailsService implements UserDetailsService {
@Transactional
public UserDetails loadUserByUsername(String s) {
try {
User user = userService.findUserByUsername(s);
Optional<User> userOptional = userService.findUserByUsername(s);
if(!userOptional.isPresent()) throw new UserNotFoundException(s);
User user = userOptional.get();
user.setAuthorities(userAuthoritiesGenerator.grantedAuthorities(user));
return user;
} catch (UserNotFoundException e){

View File

@ -1,16 +1,19 @@
package com.codesdream.ase.service;
import com.codesdream.ase.component.auth.AuthTokenGenerator;
import com.codesdream.ase.component.auth.TimestampExpiredChecker;
import com.codesdream.ase.model.auth.JSONToken;
import com.codesdream.ase.model.auth.PreValidationCode;
import com.codesdream.ase.model.permission.User;
import com.codesdream.ase.repository.auth.JSONTokenRepository;
import com.sun.org.apache.xpath.internal.operations.Bool;
import com.codesdream.ase.repository.auth.PreValidationCodeRepository;
import javafx.util.Pair;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Optional;
import java.util.UUID;
// 认证服务
@Service
@ -25,6 +28,12 @@ public class AuthService implements IAuthService {
@Resource
private AuthTokenGenerator authTokenGenerator;
@Resource
private PreValidationCodeRepository preValidationCodeRepository;
@Resource
private TimestampExpiredChecker timestampExpiredChecker;
@Override
public Optional<JSONToken> findTokenByUserName(String username) {
return jsonTokenRepository.findByUsername(username);
@ -60,4 +69,24 @@ public class AuthService implements IAuthService {
}
else return Optional.empty();
}
@Override
public String preValidationCodeGetter() {
PreValidationCode preValidationCode = new
PreValidationCode();
preValidationCode.setValue(UUID.randomUUID().toString());
preValidationCode = preValidationCodeRepository.save(preValidationCode);
return preValidationCode.getValue();
}
@Override
public boolean preValidationCodeChecker(String pvc) {
Optional<PreValidationCode> preValidationCode =
preValidationCodeRepository.findByValue(pvc);
if(preValidationCode.filter(validationCode -> timestampExpiredChecker.checkDateBeforeMaxTime(validationCode.getDate(), 60)).isPresent()){
preValidationCodeRepository.delete(preValidationCode.get());
return true;
}
else return false;
}
}

View File

@ -13,4 +13,10 @@ public interface IAuthService {
// 为用户获得一个新的API Token
Optional<String> userNewTokenGetter(String username, String clientCode);
// 获得一个新的预验证码
String preValidationCodeGetter();
// 检验预验证码
boolean preValidationCodeChecker(String pvc);
}

View File

@ -5,6 +5,7 @@ import javafx.util.Pair;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
public interface IPermissionService {
@ -19,6 +20,9 @@ public interface IPermissionService {
// 查找用户标签
Optional<Tag> findTag(String name);
// 查找用户标签
Optional<Tag> findTag(Integer id);
// 查找功能性权限容器
Optional<FunctionalPermissionContainer> findFPC(String name);
@ -41,12 +45,13 @@ public interface IPermissionService {
// 查找用户下的所有标签列表
Collection<Tag> getTagsFromUser(User user);
// 查找功能性权限容器下的所有范围性权限容器列表
Collection<FunctionalPermissionContainer> getFPCs(
PermissionContainersCollection pcc);
// 查找标签下的所有用户
Collection<User> getUsersFromTag(Tag tag);
Set<User> getUsersFromTag(Tag tag);
// 指定一对功能性权限容器与对应的范围性权限容器并添加到指定权限容器集合中
PermissionContainersCollection addRelationItemToPCC(

View File

@ -22,7 +22,7 @@ public interface IUserService {
Optional<User> findUserById(int id);
User findUserByUsername(String username);
Optional<User> findUserByUsername(String username);
// 查询用户是否存在
public Pair<Boolean, User> checkIfUserExists(String username);

View File

@ -12,9 +12,7 @@ import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;
import java.util.*;
@Service
public class PermissionService implements IPermissionService {
@ -65,6 +63,11 @@ public class PermissionService implements IPermissionService {
return tagRepository.findByName(name);
}
@Override
public Optional<Tag> findTag(Integer id) {
return tagRepository.findById(id);
}
@Override
public Optional<FunctionalPermissionContainer> findFPC(String name) {
return fpcRepository.findByName(name);
@ -117,8 +120,8 @@ public class PermissionService implements IPermissionService {
}
@Override
public Collection<User> getUsersFromTag(Tag tag) {
return new ArrayList<>(tag.getUsers());
public Set<User> getUsersFromTag(Tag tag) {
return new HashSet<>(tag.getUsers());
}
@Override

View File

@ -45,10 +45,10 @@ public class UserService implements IUserService {
}
@Override
public User findUserByUsername(String username) {
public Optional<User> findUserByUsername(String username) {
Optional<User> user = userRepository.findByUsername(username);
if(!user.isPresent()) throw new UsernameNotFoundException(username);
return user.get();
return user;
}
@Override

View File

@ -0,0 +1,28 @@
package com.codesdream.ase.test;
import com.codesdream.ase.service.AuthService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class AuthServiceTest {
@Resource
private AuthService authService;
// 测试随机验证码
@Test
public void preValidationCodeCheckerTest(){
String authStr = authService.preValidationCodeGetter();
Assert.assertTrue(authService.preValidationCodeChecker(authStr));
}
}

View File

@ -45,7 +45,10 @@ public class UserTest {
user.getUserDetail().setRealName("提姆");
userService.save(user);
user = userService.findUserByUsername("Tim");
Optional<User> userOptional = userService.findUserByUsername("Tim");
assertTrue(userOptional.isPresent());
user = userOptional.get();
assertEquals(user.getUsername(), "Tim");
assertEquals(user.getPassword(),
@ -65,9 +68,9 @@ public class UserTest {
@Test
public void UserBaseTest_2(){
User user = userService.findUserByUsername("Tim");
assertNotNull(user);
Optional<User> userOptional = userService.findUserByUsername("Tim");
assertTrue(userOptional.isPresent());
User user = userOptional.get();
user.setEnabled(false);
user.getUserAuth().setMail("saturneric@163.com");