Authored by fangyeqing

ADD:first commit

Showing 53 changed files with 4857 additions and 0 deletions

Too many changes to show.

To preserve performance only 53 of 53+ files are displayed.

.idea
*.iml
target/
\ No newline at end of file
... ...
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xkl</groupId>
<artifactId>spring-restful-authorization</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-restful-authorization-demo</name>
<url>http://maven.apache.org</url>
<!--继承spring-boot-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<!--spring-boot默认jdk版本是1.6,手动指定为1.7-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<!--依赖-->
<dependencies>
<!--网络层-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--持久层-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
<!--Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-springmvc</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
<version>2.0.8</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.8</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
... ...
package com.xkl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Spring-Boot启动类
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
... ...
package com.xkl.authorization.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在Controller的方法上使用此注解,该方法在映射时会检查用户是否登录,未登录返回401错误
* @see com.xkl.authorization.interceptor.AuthorizationInterceptor
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorization {
}
... ...
package com.xkl.authorization.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在Controller的方法参数中使用此注解,该方法在映射时会注入当前登录的User对象
* @see com.xkl.authorization.resolvers.CurrentUserMethodArgumentResolver
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {
}
... ...
package com.xkl.authorization.interceptor;
import com.xkl.authorization.annotation.Authorization;
import com.xkl.authorization.model.TokenModel;
import com.xkl.authorization.manager.TokenManager;
import com.xkl.config.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* 自定义拦截器,判断此次请求是否有权限
* @see com.xkl.authorization.annotation.Authorization
*/
@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
@Autowired
private TokenManager manager;
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//如果不是映射到方法直接通过
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//从header中得到token
String authorization = request.getHeader(Constants.AUTHORIZATION);
//验证token
TokenModel model = manager.getToken(authorization);
if (manager.checkToken(model)) {
//如果token验证成功,将token对应的用户id存在request中,便于之后注入
request.setAttribute(Constants.CURRENT_USER_ID, model.getUserId());
return true;
}
//如果验证token失败,并且方法注明了Authorization,返回401错误
if (method.getAnnotation(Authorization.class) != null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
return true;
}
}
... ...
package com.xkl.authorization.manager;
import com.xkl.authorization.model.TokenModel;
/**
* 对Token进行操作的接口
*/
public interface TokenManager {
/**
* 创建一个token关联上指定用户
* @param userId 指定用户的id
* @return 生成的token
*/
public TokenModel createToken(long userId);
/**
* 检查token是否有效
* @param model token
* @return 是否有效
*/
public boolean checkToken(TokenModel model);
/**
* 从字符串中解析token
* @param authentication 加密后的字符串
* @return
*/
public TokenModel getToken(String authentication);
/**
* 清除token
* @param userId 登录用户的id
*/
public void deleteToken(long userId);
}
... ...
package com.xkl.authorization.manager.impl;
import com.xkl.authorization.manager.TokenManager;
import com.xkl.authorization.model.TokenModel;
import com.xkl.config.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.stereotype.Component;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 通过Redis存储和验证token的实现类
* @see com.xkl.authorization.manager.TokenManager
*/
@Component
public class RedisTokenManager implements TokenManager {
private RedisTemplate<Long, String> redis;
@Autowired
public void setRedis(RedisTemplate redis) {
this.redis = redis;
//泛型设置成Long后必须更改对应的序列化方案
redis.setKeySerializer(new JdkSerializationRedisSerializer());
}
public TokenModel createToken(long userId) {
//使用uuid作为源token
String token = UUID.randomUUID().toString().replace("-", "");
TokenModel model = new TokenModel(userId, token);
//存储到redis并设置过期时间
redis.boundValueOps(userId).set(token, Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
return model;
}
public TokenModel getToken(String authentication) {
if (authentication == null || authentication.length() == 0) {
return null;
}
String[] param = authentication.split("_");
if (param.length != 2) {
return null;
}
//使用userId和源token简单拼接成的token,可以增加加密措施
long userId = Long.parseLong(param[0]);
String token = param[1];
return new TokenModel(userId, token);
}
public boolean checkToken(TokenModel model) {
if (model == null) {
return false;
}
String token = redis.boundValueOps(model.getUserId()).get();
if (token == null || !token.equals(model.getToken())) {
return false;
}
//如果验证成功,说明此用户进行了一次有效操作,延长token的过期时间
redis.boundValueOps(model.getUserId()).expire(Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
return true;
}
public void deleteToken(long userId) {
redis.delete(userId);
}
}
... ...
package com.xkl.authorization.model;
/**
* Token的Model类,可以增加字段提高安全性,例如时间戳、url签名
*/
public class TokenModel {
//用户id
private long userId;
//随机生成的uuid
private String token;
public TokenModel(long userId, String token) {
this.userId = userId;
this.token = token;
}
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
... ...
package com.xkl.authorization.resolvers;
import com.xkl.authorization.annotation.CurrentUser;
import com.xkl.config.Constants;
import com.xkl.domain.User;
import com.xkl.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
/**
* 增加方法注入,将含有CurrentUser注解的方法参数注入当前登录用户
* @see com.xkl.authorization.annotation.CurrentUser
*/
@Component
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private UserRepository userRepository;
@Override
public boolean supportsParameter(MethodParameter parameter) {
//如果参数类型是User并且有CurrentUser注解则支持
if (parameter.getParameterType().isAssignableFrom(User.class) &&
parameter.hasParameterAnnotation(CurrentUser.class)) {
return true;
}
return false;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//取出鉴权时存入的登录用户Id
Long currentUserId = (Long) webRequest.getAttribute(Constants.CURRENT_USER_ID, RequestAttributes.SCOPE_REQUEST);
if (currentUserId != null) {
//从数据库中查询并返回
return userRepository.findOne(currentUserId);
}
throw new MissingServletRequestPartException(Constants.CURRENT_USER_ID);
}
}
... ...
package com.xkl.config;
/**
* 常量
*/
public class Constants {
/**
* 存储当前登录用户id的字段名
*/
public static final String CURRENT_USER_ID = "CURRENT_USER_ID";
/**
* token有效期(小时)
*/
public static final int TOKEN_EXPIRES_HOUR = 72;
/**
* 存放Authorization的header字段
*/
public static final String AUTHORIZATION = "authorization";
}
... ...
package com.xkl.config;
import com.xkl.authorization.interceptor.AuthorizationInterceptor;
import com.xkl.authorization.resolvers.CurrentUserMethodArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
/**
* 配置类,增加自定义拦截器和解析器
* @see com.xkl.authorization.resolvers.CurrentUserMethodArgumentResolver
* @see com.xkl.authorization.interceptor.AuthorizationInterceptor
*/
@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
@Autowired
private AuthorizationInterceptor authorizationInterceptor;
@Autowired
private CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor);
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(currentUserMethodArgumentResolver);
}
}
... ...
package com.xkl.config;
/**
* 自定义请求状态码
*/
public enum ResultStatus {
SUCCESS(100, "成功"),
USERNAME_OR_PASSWORD_ERROR(-1001, "用户名或密码错误"),
USER_NOT_FOUND(-1002, "用户不存在"),
USER_NOT_LOGIN(-1003, "用户未登录");
/**
* 返回码
*/
private int code;
/**
* 返回结果描述
*/
private String message;
ResultStatus(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
... ...
package com.xkl.config;
import com.mangofactory.swagger.configuration.SpringSwaggerConfig;
import com.mangofactory.swagger.models.dto.ApiInfo;
import com.mangofactory.swagger.plugin.EnableSwagger;
import com.mangofactory.swagger.plugin.SwaggerSpringMvcPlugin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.sql.Timestamp;
/**
* swagger-ui的配置
*/
@Configuration
@EnableSwagger
public class SwaggerConfig {
private SpringSwaggerConfig springSwaggerConfig;
@Autowired
public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) {
this.springSwaggerConfig = springSwaggerConfig;
}
@Bean
public SwaggerSpringMvcPlugin customImplementation() {
return new SwaggerSpringMvcPlugin(this.springSwaggerConfig)
.apiInfo(new ApiInfo("Spring RESTful Authorization Demo Api",
null, null, null, null, null)).
//将Timestamp类型全部转为Long类型
directModelSubstitute(Timestamp.class, Long.class);
}
}
... ...
package com.xkl.controller;
import com.xkl.authorization.annotation.Authorization;
import com.xkl.authorization.annotation.CurrentUser;
import com.xkl.authorization.manager.TokenManager;
import com.xkl.authorization.model.TokenModel;
import com.xkl.config.ResultStatus;
import com.xkl.domain.User;
import com.xkl.model.ResultModel;
import com.xkl.repository.UserRepository;
import com.wordnik.swagger.annotations.ApiImplicitParam;
import com.wordnik.swagger.annotations.ApiImplicitParams;
import com.wordnik.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 获取和删除token的请求地址,在Restful设计中其实就对应着登录和退出登录的资源映射
*/
@RestController
@RequestMapping("/login")
public class TokenController {
@Autowired
private UserRepository userRepository;
@Autowired
private TokenManager tokenManager;
@RequestMapping(method = RequestMethod.POST)
@ApiOperation(value = "登录")
public ResponseEntity<ResultModel> login(@RequestParam String username, @RequestParam String password) {
Assert.notNull(username, "username can not be empty");
Assert.notNull(password, "password can not be empty");
User user = userRepository.findByUsername(username);
if (user == null || //未注册
!user.getPassword().equals(password)) { //密码错误
//提示用户名或密码错误
return new ResponseEntity<>(ResultModel.error(ResultStatus.USERNAME_OR_PASSWORD_ERROR), HttpStatus.NOT_FOUND);
}
//生成一个token,保存用户登录状态
TokenModel model = tokenManager.createToken(user.getId());
return new ResponseEntity<>(ResultModel.ok(model), HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.DELETE)
@Authorization
@ApiOperation(value = "退出登录")
@ApiImplicitParams({
@ApiImplicitParam(name = "authorization", value = "请输入登录返回信息:userId_tokens", required = true, dataType = "string", paramType = "header"),
})
public ResponseEntity<ResultModel> logout(@CurrentUser User user) {
tokenManager.deleteToken(user.getId());
return new ResponseEntity<>(ResultModel.ok(), HttpStatus.OK);
}
}
... ...
package com.xkl.controller;
import com.xkl.authorization.annotation.Authorization;
import com.xkl.authorization.annotation.CurrentUser;
import com.xkl.domain.User;
import com.xkl.model.ResultModel;
import com.xkl.repository.UserRepository;
import com.xkl.security.AntiXSS;
import com.wordnik.swagger.annotations.ApiImplicitParam;
import com.wordnik.swagger.annotations.ApiImplicitParams;
import com.wordnik.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by win7 on 2016/10/19.
*/
@RestController
@RequestMapping("/userInfo")
public class UserInfoController {
@Autowired
private UserRepository userRepository;
@RequestMapping(method = RequestMethod.GET)
@Authorization
@ApiOperation(value = "获取用户昵称")
@ApiImplicitParams({
@ApiImplicitParam(name = "authorization", value = "请输入登录返回信息:userId_tokens", required = true, dataType = "string", paramType = "header"),
})
public ResponseEntity<ResultModel> getUserNickName(@CurrentUser User user) {
String dickName=user.getNickname();
return new ResponseEntity<>(ResultModel.ok(dickName), HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.PUT)
@Authorization
@AntiXSS
@ApiOperation(value = "修改用户昵称")
@ApiImplicitParams({
@ApiImplicitParam(name = "authorization", value = "请输入登录返回信息:userId_tokens", required = true, dataType = "string", paramType = "header"),
})
public ResponseEntity<ResultModel> modUserNickName(@CurrentUser User user,@RequestParam String userNickName) {
Assert.notNull(userNickName, "userDickName can not be empty");
user.setNickname(userNickName);
userRepository.save(user);
return new ResponseEntity<>(ResultModel.ok(), HttpStatus.OK);
}
}
... ...
package com.xkl.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* 用户数据的domain类
*/
@Entity
@Table(name = "user_")
public class User {
//用户名
@Column(name = "username_")
private String username;
//密码
@Column(name = "password_")
private String password;
//用户id
@Id
@Column(name = "id_")
private long id;
//昵称
@Column(name = "nickname_")
private String nickname;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
}
... ...
package com.xkl.model;
import com.xkl.config.ResultStatus;
/**
* 自定义返回结果
*/
public class ResultModel {
/**
* 返回码
*/
private int code;
/**
* 返回结果描述
*/
private String message;
/**
* 返回内容
*/
private Object content;
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public Object getContent() {
return content;
}
public ResultModel(int code, String message) {
this.code = code;
this.message = message;
this.content = "";
}
public ResultModel(int code, String message, Object content) {
this.code = code;
this.message = message;
this.content = content;
}
public ResultModel(ResultStatus status) {
this.code = status.getCode();
this.message = status.getMessage();
this.content = "";
}
public ResultModel(ResultStatus status, Object content) {
this.code = status.getCode();
this.message = status.getMessage();
this.content = content;
}
public static ResultModel ok(Object content) {
return new ResultModel(ResultStatus.SUCCESS, content);
}
public static ResultModel ok() {
return new ResultModel(ResultStatus.SUCCESS);
}
public static ResultModel error(ResultStatus error) {
return new ResultModel(error);
}
}
... ...
package com.xkl.repository;
import com.xkl.domain.User;
import org.springframework.data.repository.CrudRepository;
/**
* User类的CRUD操作
* @see com.xkl.domain.User
*/
public interface UserRepository extends CrudRepository<User, Long> {
public User findByUsername(String username);
}
... ...
package com.xkl.security;
import java.lang.annotation.*;
/**
* 防止XSS攻击注解,作用在DAO层,在写入前过滤数据(save | update)
* Created by win7 on 2016/10/21.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AntiXSS {
}
... ...
package com.xkl.security;
import lombok.extern.apachecommons.CommonsLog;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
/**
* 对String或者Entity中的String进行AntiXSS处理
* <p/>
* Created by win7 on 2016/10/21.
*/
@Service
@Aspect
@CommonsLog
public class AntiXSSAspect {
/**
* 定义切点,定位到@AntiXSS注解的地方
*/
@Pointcut("@annotation(com.xkl.security.AntiXSS)")
public void antiXSSPointCut() {
}
/**
* 对String类型活包含String类型的POJO进行antiXSS处理
*
* @param point
*/
@Around("antiXSSPointCut()")
public Object doAround(ProceedingJoinPoint point) {
Object result = null;
Object args[] = point.getArgs();
try {
antiXSS(args);
result = point.proceed(args);
} catch (Throwable throwable) {
log.error(point.getSignature().getName() + " failed");
}
return result;
}
/**
* antiXSS处理
*
* @param args
*/
private void antiXSS(Object[] args) {
if (args == null) {
return;
}
for (int i = 0; i < args.length; i++) {
if (args[i] == null) {
continue;
}
if (args[i] instanceof String) {//String类型
args[i] = AntiXSSUtil.antiXSS((String) args[i]);
}
if (!isPrimitive(args[i])) {//非基本类型
antiXSSEntity(args[i]);
}
}
}
/**
* 对Entity进行antiXSS
*
* @param object
* @return 处理后的结果
*/
private void antiXSSEntity(Object object) {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
Object arg = field.get(object);
if (arg instanceof String) {
arg = AntiXSSUtil.antiXSS((String) arg);
field.set(object, arg);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* 判断是否是基本类型
*
* @param arg
* @return
*/
private boolean isPrimitive(Object arg) {
try {
/************ 基本类型中包含Class<T> TYPE字段 **********/
Field field = arg.getClass().getDeclaredField("TYPE");
field.setAccessible(true);
Class fieldClass = (Class) field.get(arg);
if (fieldClass.isPrimitive()) {
return true;
}
} catch (Exception e) {
return false;
}
return true;
}
}
... ...
package com.xkl.security;
import org.apache.oro.text.regex.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 防XSS攻击
* <p>
* Created by win7 on 2016/10/21.
*/
public class AntiXSSUtil {
static final Pattern SCRIPT_TAG_PATTERN = Pattern.compile("<script[^>]*>.*</script[^>]*>", Pattern.CASE_INSENSITIVE);
static final PatternCompiler pc = new Perl5Compiler();
static final PatternMatcher matcher = new Perl5Matcher();
public static String antiXSS(String content) {
if (content == null || content.equals("")) {
return "";
}
String old = content;
String ret = _antiXSS(content);
while (!ret.equals(old)) {
old = ret;
ret = _antiXSS(ret);
}
return ret;
}
private static String _antiXSS(String content) {
try {
return stripAllowScriptAccess(
stripProtocol(stripCssExpression(
stripAsciiAndHex(stripEvent(stripScriptTag(content))))));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static String stripScriptTag(String content) {
Matcher m = SCRIPT_TAG_PATTERN.matcher(content);
content = m.replaceAll("");
return content;
}
private static String stripEvent(String content) throws Exception {
String[] events = {
"onmouseover", "onmouseout", "onmousedown", "onmouseup",
"onmousemove", "onclick", "ondblclick", "onkeypress", "onkeydown",
"onkeyup", "ondragstart", "onerrorupdate", "onhelp",
"onreadystatechange", "onrowenter", "onrowexit", "onselectstart",
"onload", "onunload", "onbeforeunload", "onblur", "onerror",
"onfocus", "onresize", "onscroll", "oncontextmenu"
};
for (String event : events) {
org.apache.oro.text.regex.Pattern p = pc.compile("(<[^>]*)("
+ event + ")([^>]*>)", Perl5Compiler.CASE_INSENSITIVE_MASK);
if (null != p)
content = Util.substitute(matcher, p, new Perl5Substitution(
"$1" + event.substring(2) + "$3"), content,
Util.SUBSTITUTE_ALL);
}
return content;
}
private static String stripAsciiAndHex(String content) throws Exception {
// filter &# \00xx
org.apache.oro.text.regex.Pattern p = pc.compile(
"(<[^>]*)(&#|\\\\00)([^>]*>)",
Perl5Compiler.CASE_INSENSITIVE_MASK);
if (null != p)
content = Util
.substitute(matcher, p, new Perl5Substitution("$1$3"),
content, Util.SUBSTITUTE_ALL);
return content;
}
private static String stripCssExpression(String content) throws Exception {
org.apache.oro.text.regex.Pattern p = pc.compile(
"(<[^>]*style=.*)/\\*.*\\*/([^>]*>)",
Perl5Compiler.CASE_INSENSITIVE_MASK);
if (null != p) {
content = Util.substitute(matcher, p, new Perl5Substitution("$1$2"), content, Util.SUBSTITUTE_ALL);
}
p = pc.compile("(<[^>]*style=[^>]+)(expression|javascript|vbscript|-moz-binding)([^>]*>)",
Perl5Compiler.CASE_INSENSITIVE_MASK);
if (null != p) {
content = Util.substitute(matcher, p, new Perl5Substitution("$1$3"), content, Util.SUBSTITUTE_ALL);
}
p = pc.compile("(<style[^>]*>.*)/\\*.*\\*/(.*</style[^>]*>)", Perl5Compiler.CASE_INSENSITIVE_MASK);
if (null != p) {
content = Util.substitute(matcher, p, new Perl5Substitution("$1$2"), content, Util.SUBSTITUTE_ALL);
}
p = pc.compile("(<style[^>]*>[^>]+)(expression|javascript|vbscript|-moz-binding)(.*</style[^>]*>)",
Perl5Compiler.CASE_INSENSITIVE_MASK);
if (null != p) {
content = Util.substitute(matcher, p, new Perl5Substitution("$1$3"), content, Util.SUBSTITUTE_ALL);
}
return content;
}
private static String stripProtocol(String content) throws Exception {
String[] protocols = {
"javascript", "vbscript", "livescript", "ms-its", "mhtml", "data",
"firefoxurl", "mocha"
};
for (String protocol : protocols) {
org.apache.oro.text.regex.Pattern p = pc.compile("(<[^>]*)" + protocol + ":([^>]*>)",
Perl5Compiler.CASE_INSENSITIVE_MASK);
if (null != p)
content = Util.substitute(matcher, p, new Perl5Substitution("$1/$2"), content, Util.SUBSTITUTE_ALL);
}
return content;
}
private static String stripAllowScriptAccess(String content)
throws Exception {
org.apache.oro.text.regex.Pattern p = pc.compile(
"(<[^>]*)AllowScriptAccess([^>]*>)",
Perl5Compiler.CASE_INSENSITIVE_MASK);
if (null != p)
content = Util.substitute(matcher, p, new Perl5Substitution(
"$1Allow_Script_Access$2"), content, Util.SUBSTITUTE_ALL);
return content;
}
}
... ...
#MySQL
spring.datasource.url=jdbc:mysql://db.hanhezy.com:4096/hanhe_test?useUnicode=true&autoReconnect=true&failOverReadOnly=false&zeroDateTimeBehavior=round&autoReconnect=true
spring.datasource.username=hanhe
spring.datasource.password=HANhetest2016
#Redis
#spring.redis.host=127.0.0.1
#spring.redis.password=foobared
spring.redis.host=r-m5e7cedd3124afd4.redis.rds.aliyuncs.com
spring.redis.password=r-m5e7cedd3124afd4:XIkaiLURedis2016
spring.redis.port=6379
\ No newline at end of file
... ...
create table user_ (
username_ varchar(20) unique not null,
password_ varchar(20) not null,
id_ int unsigned auto_increment,
nickname_ varchar(20) not null,
primary key(id_)
);
insert into user_ (username_, password_, nickname_) values ('admin', 'password', 'admin' );
\ No newline at end of file
... ...
/* Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org> */
.swagger-section pre code {
display: block;
padding: 0.5em;
background: #F0F0F0;
}
.swagger-section pre code,
.swagger-section pre .subst,
.swagger-section pre .tag .title,
.swagger-section pre .lisp .title,
.swagger-section pre .clojure .built_in,
.swagger-section pre .nginx .title {
color: black;
}
.swagger-section pre .string,
.swagger-section pre .title,
.swagger-section pre .constant,
.swagger-section pre .parent,
.swagger-section pre .tag .value,
.swagger-section pre .rules .value,
.swagger-section pre .rules .value .number,
.swagger-section pre .preprocessor,
.swagger-section pre .ruby .symbol,
.swagger-section pre .ruby .symbol .string,
.swagger-section pre .aggregate,
.swagger-section pre .template_tag,
.swagger-section pre .django .variable,
.swagger-section pre .smalltalk .class,
.swagger-section pre .addition,
.swagger-section pre .flow,
.swagger-section pre .stream,
.swagger-section pre .bash .variable,
.swagger-section pre .apache .tag,
.swagger-section pre .apache .cbracket,
.swagger-section pre .tex .command,
.swagger-section pre .tex .special,
.swagger-section pre .erlang_repl .function_or_atom,
.swagger-section pre .markdown .header {
color: #800;
}
.swagger-section pre .comment,
.swagger-section pre .annotation,
.swagger-section pre .template_comment,
.swagger-section pre .diff .header,
.swagger-section pre .chunk,
.swagger-section pre .markdown .blockquote {
color: #888;
}
.swagger-section pre .number,
.swagger-section pre .date,
.swagger-section pre .regexp,
.swagger-section pre .literal,
.swagger-section pre .smalltalk .symbol,
.swagger-section pre .smalltalk .char,
.swagger-section pre .go .constant,
.swagger-section pre .change,
.swagger-section pre .markdown .bullet,
.swagger-section pre .markdown .link_url {
color: #080;
}
.swagger-section pre .label,
.swagger-section pre .javadoc,
.swagger-section pre .ruby .string,
.swagger-section pre .decorator,
.swagger-section pre .filter .argument,
.swagger-section pre .localvars,
.swagger-section pre .array,
.swagger-section pre .attr_selector,
.swagger-section pre .important,
.swagger-section pre .pseudo,
.swagger-section pre .pi,
.swagger-section pre .doctype,
.swagger-section pre .deletion,
.swagger-section pre .envvar,
.swagger-section pre .shebang,
.swagger-section pre .apache .sqbracket,
.swagger-section pre .nginx .built_in,
.swagger-section pre .tex .formula,
.swagger-section pre .erlang_repl .reserved,
.swagger-section pre .prompt,
.swagger-section pre .markdown .link_label,
.swagger-section pre .vhdl .attribute,
.swagger-section pre .clojure .attribute,
.swagger-section pre .coffeescript .property {
color: #8888ff;
}
.swagger-section pre .keyword,
.swagger-section pre .id,
.swagger-section pre .phpdoc,
.swagger-section pre .title,
.swagger-section pre .built_in,
.swagger-section pre .aggregate,
.swagger-section pre .css .tag,
.swagger-section pre .javadoctag,
.swagger-section pre .phpdoc,
.swagger-section pre .yardoctag,
.swagger-section pre .smalltalk .class,
.swagger-section pre .winutils,
.swagger-section pre .bash .variable,
.swagger-section pre .apache .tag,
.swagger-section pre .go .typename,
.swagger-section pre .tex .command,
.swagger-section pre .markdown .strong,
.swagger-section pre .request,
.swagger-section pre .status {
font-weight: bold;
}
.swagger-section pre .markdown .emphasis {
font-style: italic;
}
.swagger-section pre .nginx .built_in {
font-weight: normal;
}
.swagger-section pre .coffeescript .javascript,
.swagger-section pre .javascript .xml,
.swagger-section pre .tex .formula,
.swagger-section pre .xml .javascript,
.swagger-section pre .xml .vbscript,
.swagger-section pre .xml .css,
.swagger-section pre .xml .cdata {
opacity: 0.5;
}
.swagger-section .swagger-ui-wrap {
line-height: 1;
font-family: "Droid Sans", sans-serif;
max-width: 960px;
margin-left: auto;
margin-right: auto;
}
.swagger-section .swagger-ui-wrap b,
.swagger-section .swagger-ui-wrap strong {
font-family: "Droid Sans", sans-serif;
font-weight: bold;
}
.swagger-section .swagger-ui-wrap q,
.swagger-section .swagger-ui-wrap blockquote {
quotes: none;
}
.swagger-section .swagger-ui-wrap p {
line-height: 1.4em;
padding: 0 0 10px;
color: #333333;
}
.swagger-section .swagger-ui-wrap q:before,
.swagger-section .swagger-ui-wrap q:after,
.swagger-section .swagger-ui-wrap blockquote:before,
.swagger-section .swagger-ui-wrap blockquote:after {
content: none;
}
.swagger-section .swagger-ui-wrap .heading_with_menu h1,
.swagger-section .swagger-ui-wrap .heading_with_menu h2,
.swagger-section .swagger-ui-wrap .heading_with_menu h3,
.swagger-section .swagger-ui-wrap .heading_with_menu h4,
.swagger-section .swagger-ui-wrap .heading_with_menu h5,
.swagger-section .swagger-ui-wrap .heading_with_menu h6 {
display: block;
clear: none;
float: left;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
width: 60%;
}
.swagger-section .swagger-ui-wrap table {
border-collapse: collapse;
border-spacing: 0;
}
.swagger-section .swagger-ui-wrap table thead tr th {
padding: 5px;
font-size: 0.9em;
color: #666666;
border-bottom: 1px solid #999999;
}
.swagger-section .swagger-ui-wrap table tbody tr:last-child td {
border-bottom: none;
}
.swagger-section .swagger-ui-wrap table tbody tr.offset {
background-color: #f0f0f0;
}
.swagger-section .swagger-ui-wrap table tbody tr td {
padding: 6px;
font-size: 0.9em;
border-bottom: 1px solid #cccccc;
vertical-align: top;
line-height: 1.3em;
}
.swagger-section .swagger-ui-wrap ol {
margin: 0px 0 10px;
padding: 0 0 0 18px;
list-style-type: decimal;
}
.swagger-section .swagger-ui-wrap ol li {
padding: 5px 0px;
font-size: 0.9em;