这里使用到了Redis来实现JWT的过期刷新,话不多说,具体的实现代码如下
1.自定义AuthenticationToken类
public final class JwtToken implements AuthenticationToken {
private static final long serialVersionUID = 1L;
private String jwttoken;
public JwtToken(String jwttoken) {
super();
this.jwttoken = jwttoken;
}
@Override
public Object getCredentials() {
return jwttoken;
}
@Override
public Object getPrincipal() {
return jwttoken;
}
}
2.自定义一个JWT拦截器类
public class JWTFilter extends BasicHttpAuthenticationFilter {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
RedisUtil redisUtils;
@Autowired
private UserService userService;
private AntPathMatcher pathMatcher = new AntPathMatcher();
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
boolean isauth =
Constant.URLS.stream()
.filter(x->!Objects.equals("/**",x))
.anyMatch(x->pathMatcher.matches(x,((HttpServletRequest)request).getRequestURI()));
if (isauth || ((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {
return true;
}
AuthenticationToken token = createToken(request,response);
if (token.getCredentials() == null) {
logger.info("未登录.....................");
response(response,ResultUtil.resultCodes(ResponseEnum.OAUTH));
}else{
try {
SecurityUtils.getSubject().login(token);
return true;
} catch (AuthenticationException e) {
logger.error("AuthenticationException.....................",e);;
if(e instanceof ExpiredCredentialsException){
return refreshToken(request,response);
}else response(response,ResultUtil.resultErr(e.getMessage()));
e.printStackTrace();
}
}
return false;
}
/**
* 此处为AccessToken刷新,进行判断RefreshToken是否过期,未过期就返回新的AccessToken且继续正常访问
* @param servletRequest
* @param servletResponse
* @return
*/
private boolean refreshToken(ServletRequest request, ServletResponse response) {
logger.info("刷新TOKEN...............................");
HttpServletRequest request1 = (HttpServletRequest) request;
HttpServletResponse response1 = (HttpServletResponse) response;
String oldToken = getToken(request1);
String uid = redisUtils.getUidByToken(oldToken,Constant.JWT_TOKEN);
if (uid != null) {
UserMsg userMsg = userService.findById(Integer.valueOf(uid));
String newToken = JwtUtils.generateToken(userMsg);
JwtToken jwtToken = new JwtToken(newToken);
redisUtils.set(Constant.JWT_TOKEN+uid,newToken,Constant.MAX_EXPIRED);
CookieUtil.addcookie(ImmutableMap.of("Authorization",newToken),request1,response1);
SecurityUtils.getSubject().login(jwtToken);
return true;
}
return false;
}
private String getToken(HttpServletRequest request){
String token = request.getHeader("Authorization");
if(token==null)token = CookieUtil.getcookie(request,"Authorization");
return token;
}
/**
* 返回错误信息
*
* @param response
* @param code
* @param msg
*/
@SuppressWarnings("deprecation")
private void response(ServletResponse response,ResultUtil<?> resultUtil) {
try {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
httpResponse.getWriter().write(JSON.toJSONString(resultUtil));
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
/**
* 支持跨域
*
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers",
"Authorization,Origin,X-Requested-With,Content-Type,Accept");
// 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(httpServletRequest, httpServletResponse);
}
@Override
protected AuthenticationToken createToken(ServletRequest arg0, ServletResponse arg1) {
HttpServletRequest request = (HttpServletRequest) arg0;
String token = getToken(request);
return new JwtToken(token);
}
}
3.自定义登陆验证策略
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
RedisUtil redisutils;
@Override
public boolean supports(AuthenticationToken token) {
return true;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();
UserMsg userMsg = (UserMsg) principal.getPrimaryPrincipal();
Set<String> roles = Stream.of(userMsg.getIsadmin() == 1 ? "admin" : "user").collect(Collectors.toSet());
Set<String> permissions = Stream
.of(userMsg.getIsadmin() == 1 ? "select,delete,update,insert" : "select,update,insert")
.flatMap(x -> Arrays.stream(x.split(","))).collect(Collectors.toSet());
// 添加角色
auth.setRoles(roles);
// 添加权限
auth.setStringPermissions(permissions);
return auth;
}
public static void main(String[] args) {
System.out.println(new Md5Hash("1230","450",3));
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
if (token instanceof JwtToken) {
String jwttoken = (String) token.getPrincipal();
String username = JwtUtils.getUsernameFromToken(jwttoken);
if (username == null)throw new ExpiredCredentialsException();//token过期这里会尝试刷新token
UserMsg usermsg = userService.findByName(username);
System.out.println("usermsg "+usermsg.getPassword());
String md5Hash = new Md5Hash(jwttoken,"jwttoken",5).toHex();
return new SimpleAuthenticationInfo(usermsg,md5Hash,ByteSource.Util.bytes("jwttoken"),getName());
}
UsernamePasswordToken usernames = (UsernamePasswordToken) token;
String username = usernames.getUsername();
String password = new String(usernames.getPassword());
System.out.println("Username "+username);
System.out.println("password "+password);
UserMsg usermsg = userService.findByName(username);
System.out.println("usermsg" +usermsg);
if (usermsg == null) {
throw new UnknownAccountException();
}
if (redisutils.get(usermsg.getUsername()) != null) {
Integer pass_count = Integer.valueOf(redisutils.get(usermsg.getUsername()));
if (pass_count >= 5)throw new ExcessiveAttemptsException();
}
String md5Hash = new Md5Hash(password,usermsg.getSalt(),5).toHex();
if (!Objects.equals(usermsg.getPassword(),md5Hash)) {
//记录用户密码错误的次数
if(redisutils.hasKey(usermsg.getUsername())){
redisutils.incr(usermsg.getUsername(),1);
}else redisutils.set(usermsg.getUsername(),"1",Constant.MAX_EXPIRED);
throw new IncorrectCredentialsException();
}
return new SimpleAuthenticationInfo(usermsg,md5Hash,ByteSource.Util.bytes(usermsg.getSalt()),getName());
}
}
4.定义Shiro配置类
@Configuration
public class ShiroConfig {
/**
* 自定义jwt认证策略
* @return
*/
// @Bean("jwtRealm")
// public JwtRealm jwtRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
// JwtRealm myShiroRealm = new JwtRealm();
// myShiroRealm.setCachingEnabled(true);
// myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
// return myShiroRealm;
// }
/**
* 自定义用户登录认证策略
* @return
*/
@Bean("userRealm")
public UserRealm userRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
UserRealm myShiroRealm = new UserRealm();
myShiroRealm.setCachingEnabled(true);
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
return myShiroRealm;
}
/**
* 禁用Session
* @return
*/
@Bean("sessionManager")
public DefaultSessionManager sessionManager() {
DefaultSessionManager sessionManager = new DefaultSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(false);
return sessionManager;
}
/**
* 禁用Session
* @return
*/
@Bean("defaultSessionStorageEvaluator")
public DefaultSessionStorageEvaluator defaultSessionStorageEvaluator () {
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
return defaultSessionStorageEvaluator;
}
/**
* MD5加密
* @return
*/
@Bean("hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashed = new HashedCredentialsMatcher();
hashed.setHashAlgorithmName("MD5");
hashed.setHashIterations(5);
return hashed;
}
@Bean("subjectDAO")
public DefaultSubjectDAO subjectDAO(DefaultSessionStorageEvaluator defaultSessionStorageEvaluator) {
DefaultSubjectDAO defaultSubjectDAO = new DefaultSubjectDAO();
defaultSubjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
return defaultSubjectDAO;
}
@Bean
public FilterRegistrationBean<Filter> delegatingFilterProxy(){
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<Filter>();
DelegatingFilterProxy proxy = new DelegatingFilterProxy();
proxy.setTargetFilterLifecycle(true);
proxy.setTargetBeanName("shiroFilter");
filterRegistrationBean.setFilter(proxy);
return filterRegistrationBean;
}
@Bean("securityManager")
public SecurityManager securityManager(
UserRealm userRealm,
DefaultSubjectDAO subjectDAO,
DefaultSessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
securityManager.setSubjectDAO(subjectDAO);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
@Bean("jwtFilter")
public JWTFilter jwtFilter() {
return new JWTFilter();
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager,JWTFilter jwtFilter) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
Map<String, Filter> filters = new HashMap<>();
filters.put("authc",jwtFilter);
shiroFilter.setFilters(filters);
shiroFilter.setFilterChainDefinitionMap(Constant.URL_MAP);
shiroFilter.setLoginUrl("/page/login_page");
shiroFilter.setSuccessUrl("/page/index_page");
shiroFilter.setUnauthorizedUrl("/page/err_page");
return shiroFilter;
}
@Bean(name = "advisorAutoProxyCreator")
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean("authorizationAttributeSourceAdvisor")
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
5.定义生成图形验证码和短信验证码的类
@Component
public class ValidatedUtil {
private String SMS_Url = "http://gbk.api.smschinese.cn";
private Random random = new Random();
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class ImageCode{
private BufferedImage image;
private String code;
private LocalDateTime expireTime;
public ImageCode(BufferedImage image, String code, long expireIn) {
this.code = code;
this.image = image;
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
}
public boolean isExpried() {
return LocalDateTime.now().isAfter(getExpireTime());
}
}
/**
* 生成验证码图片
* @return
*/
public ImageCode getImageCode(){
BufferedImage image = new BufferedImage(Constants.width,Constants.height,BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, Constants.width,Constants.height);
g.setColor(getRandColor(160,200));
for (int i = 0; i < 155; i++) {
int x = random.nextInt(Constants.width);
int y = random.nextInt(Constants.height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x, y, x + xl, y + yl);
}
g.setFont(new Font("黑体",Font.BOLD,30));
FontMetrics fontMetrics = g.getFontMetrics();
String sRand = random(Constants.length);
for(int i = 0; i < sRand.length();i++){
String fonts = String.valueOf(sRand.charAt(i));
g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
int width = fontMetrics.stringWidth(fonts)*i+10,height=20;
g.rotate(Math.toRadians(random.nextInt(5)),width,height);
g.drawString(fonts,width,height);
}
g.dispose();
return new ImageCode(image,sRand,Constants.image_expire_second);
}
/**
* 生成随机背景条纹
* @param fc
* @param bc
* @return
*/
private Color getRandColor(int fc, int bc) {
Random random = new Random();
if (fc > 255)fc = 255;
if (bc > 255) bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
/**
* 生成指定长度的英文字符
* @param length
* @return
*/
private String random(int length){
length = length>26?26:length<1?5:length;
StringBuilder string = new StringBuilder();
String[] chars = IntStream.range(0,26)
.mapToObj(x->String.valueOf(((char)(97+x))))
.toArray(String[]::new);
boolean[] nmber = new boolean[chars.length];
do{
int ints = random.nextInt(chars.length);
if (nmber[ints] == false)string.append(chars[ints]);
nmber[ints] = true;
}while(string.length()<length);
return string.toString();
}
/**
* 发送手机验证码
* @param phone 接收验证码的手机号
* @param length 验证码长度
* @return
*/
public SmsCode getSmsCode(String phone,int length){
String validatedCode = IntStream.range(0,length)
.map(x->random.nextInt(10))
.mapToObj(String::valueOf)
.collect(Collectors.joining());
Map<String,String> map = new LinkedHashMap<>();
map.put("Uid","你的ID");
map.put("Key","你的Key");
map.put("smsMob",phone);//发生的手机号
map.put("smsText","你的验证码为 "+validatedCode+" 请勿提供他人使用");//发送的内容
String message = (String)HttpUtil.request(SMS_Url,map,"POST");
System.err.println("sendsms() "+message);
return new SmsCode(phone, validatedCode, message);
}
}
6.用于调用短信接口的方法
public static Object request(String url, Map<String, String> maps, String method) {
try {
isNull(url, maps, method);
okhttp3.Request.Builder rbuilder = new Request.Builder().header("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36");
okhttp3.FormBody.Builder fbuilder = new FormBody.Builder(Charset.forName("GBK"));
if (maps != null && maps.size() > 0)
maps.forEach((a, b) -> fbuilder.add(a, b));
Request requests = method.equalsIgnoreCase("get") ? rbuilder.get().url(url).build()
: rbuilder.method(method, fbuilder.build()).url(url).build();
Response response = OKHTTP.newCall(requests).execute();
String type = response.header("content-type");
return type.contains("application/json") ? JSON.parseObject(response.body().string())
: response.body().string();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
7.定义JWT生成工具类
public abstract class JwtUtils {
//private static final String secret = UUID.randomUUID().toString().replace("-","");
private static final String secret = "abcdefg";
private static final Long expiration = 60*10*1000L;//令牌过期时间10分钟
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private static String generateToken(Map<String, Object> claims) {
Date expirationDate = new Date(System.currentTimeMillis() + expiration);
return Jwts.builder()
.setClaims(claims)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private static Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
public static String generateToken(UserMsg userMsg) {
Map<String,Object> claims = new HashMap<>();
claims.put("username",userMsg.getUsername());
claims.put("uid",userMsg.getUid());
claims.put("header",userMsg.getHeader());
claims.put("lasttime",LocalDateTime.now());
return generateToken(claims);
}
public static <T> T getUserByToken(String token,Class<T> classs) {
T user = null;
try {
Claims claims = getClaimsFromToken(token);
if(claims==null)return null;
user = classs.newInstance();
for(Field field : classs.getDeclaredFields()){
String name = field.getName();
if(!claims.containsKey(name))continue;
field.setAccessible(true);
field.set(user,claims.get(name));
}
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
/**
* 从令牌中获取用户名
* @param token 令牌
* @return 用户名
*/
public static String getUsernameFromToken(String token) {
String username;
try {
Claims claims = getClaimsFromToken(token);
username = claims.get("username",String.class);
} catch (Exception e) {
username = null;
}
return username;
}
/**
* 判断令牌是否过期
*
* @param token 令牌
* @return 是否过期
*/
public static Boolean isTokenExpired(String token) {
try {
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration.before(new Date());
} catch (Exception e) {
return true;
}
}
/**
* 刷新令牌
* @param token 原令牌
* @return 新令牌
*/
public static String refreshToken(String token) {
String refreshedToken;
try {
Claims claims = getClaimsFromToken(token);
claims.put(Claims.ISSUED_AT, new Date());
refreshedToken = generateToken(claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
}
上面的都准备好了接下来就开始编写接口方法了
1.定义用于获取图形验证码和发送短信验证码的Controller
@RestController
@RequestMapping("validate")
public class ValidateController extends BaseController {
@Autowired
RedisUtil redisutils;
@Autowired
ValidatedUtil validatedUtil;
// @Autowired
// SessionStrategy sessionStrategy;
/**
* 获取短信验证码
* @param phone
* @return
*/
@ApiOperation("获取短信验证码")
@RequestLimit
@RequestMapping(value = "/sendSms", method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultUtil<?> sendSms(@Validated(Reg.class) @ApiParam SmsCode phone){
SmsCode smscode = validatedUtil.getSmsCode(phone.getPhone(),6);
redisutils.set(phone.getPhone(),smscode.getCode(),60*10);
String response = smscode.getMessage();
if(response.matches("-?\\d+") && Integer.valueOf(response)>0)return ResultUtil.resultOK();
return ResultUtil.resultErr(response);
}
/**
* 获取图形验证码
* @param request
* @param response
*/
@ApiOperation("获取图形验证码")
@RequestMapping(value = "/imageCode", method = RequestMethod.POST)
public void imageCode(@ApiParam HttpServletRequest request,@ApiParam HttpServletResponse response){
try {
ImageCode imagecode = validatedUtil.getImageCode();
String token = UUID.randomUUID().toString().replace("-","");
redisutils.set(token,imagecode.getCode(),60L);
CookieUtil.addcookie(ImmutableMap.of(Constants.session_key,token), request, response);
//sessionStrategy.setAttribute(new ServletWebRequest(request),Constants.session_key,imagecode);
response.setContentType("image/jpeg");
ImageIO.write(imagecode.getImage(),"JPEG",response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.定义用户登陆Controller
@Api("用户Controller")
@RestController
//@RefreshScope
@RequestMapping("user")
@Validated
public class Usercontroller extends BaseController{
@Value("${user.home}")
private String home;
@Value("${user.pass}")
private String pass;
@Autowired
RedisUtil redisutils;
// @Autowired
// SessionStrategy sessionStrategy;
@Autowired
UserService userSerivce;
/**
* 图形验证码登陆
* @param userMsg
* @param validated
* @param request
* @return
*/
@ApiOperation("图形验证码登陆接口")
@RequestMapping(value = "/login",method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultUtil<?> login(@Validated(Login.class) UserMsg userMsg,@NotEmpty(message="验证码为空") String validated,HttpServletRequest request,HttpServletResponse response) {
UsernamePasswordToken passwordtoken = new UsernamePasswordToken(userMsg.getUsername(),userMsg.getPassword());
Subject subjects = SecurityUtils.getSubject();
subjects.login(passwordtoken);
validate(validated,request);
UserMsg usermsgs = (UserMsg)subjects.getPrincipal();
String jwt_token = JwtUtils.generateToken(usermsgs);
redisutils.set(Constant.JWT_TOKEN + usermsgs.getUid(), jwt_token, Constant.MAX_EXPIRED);
CookieUtil.addcookie(ImmutableMap.of("Authorization",jwt_token),request,response);
return ResultUtil.resultOK();
}
/**
* 注册接口
* @param userMsg
* @return
*/
@ApiOperation("注册接口")
@RequestMapping(value = "/reg",method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultUtil<?> reg(@Validated(Reg.class) UserMsg userMsg) {
UserMsg user = userSerivce.findByName(userMsg.getUsername());
if(user!=null)throw new RuntimeException("用户已存在");
String salt = UUID.randomUUID().toString().replace("-","");
String md5Hash = new Md5Hash(userMsg.getPassword(),salt,5).toHex();
userMsg.setPassword(md5Hash);
userMsg.setSalt(salt);
UserMsg admin = userSerivce.findByAdmin();
userMsg.setIsadmin(admin!=null?0:1);
userMsg.setIsdelete(0);
userSerivce.save(userMsg);
return ResultUtil.resultOK();
}
/**
* 短信验证码登陆
* @param validated
* @param request
* @param response
* @return
*/
@ApiOperation("短信验证码登陆")
@RequestMapping(value = "/smslogin",method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultUtil<?> smslogin(@Validated(Login.class) SmsCode validated,HttpServletRequest request,HttpServletResponse response) {
if(!redisutils.hasKey(validated.getPhone()))throw new RuntimeException("验证码已过期");
if(!Objects.equals(validated.getCode(),redisutils.get(validated.getPhone())))throw new RuntimeException("验证码错误");
UserMsg smsUser = new UserMsg();
smsUser.setUsername("用户"+validated.getPhone());
smsUser.setPhone(validated.getPhone());
smsUser.setIsadmin(0);
smsUser.setIsdelete(0);
UserMsg userMsg = userSerivce.save(smsUser);
String token = JwtUtils.generateToken(smsUser);
redisutils.set(Constant.JWT_TOKEN+userMsg.getUid(),token,Constant.MAX_EXPIRED);
CookieUtil.addcookie(ImmutableMap.of("Authorization",token),request,response);
return ResultUtil.resultOK();
}
@RequestMapping(value = "/logout",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultUtil<?> logout(HttpServletRequest request,HttpServletResponse response) {
String token = request.getHeader("Authorization");
if(token==null)token = CookieUtil.getcookie(request,"Authorization");
if(token==null)return ResultUtil.resultCodes(ResponseEnum.LOGOUTERR);
CookieUtil.addcookie(ImmutableMap.of("Authorization","del"),request,response);
redisutils.delvalues(Constant.JWT_TOKEN,token);
return ResultUtil.resultOK();
}
private void validate(String validated,HttpServletRequest request) {
String image_token = CookieUtil.getcookie(request,Constants.session_key);
if(!redisutils.hasKey(image_token))throw new RuntimeException("验证码不存在");
if (!Objects.equals(redisutils.get(image_token),validated))throw new RuntimeException("验证码错误");
}
//@RequiresPermissions("user")
@RequiresRoles(logical=Logical.OR,value={"user","admin"})
@RequestMapping(value = "/userinfo",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultUtil<?> getuserinfo(){
return ResultUtil.resultOK(SecurityUtils.getSubject().getPrincipal());
}
@RequiresRoles("admin")
@RequestMapping(value = "/getuser/{uid:\\d+}",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultUtil<?> getUserId(@PathVariable("uid") Integer uid){
return ResultUtil.resultOK(userSerivce.findById(uid));
}
@RequiresRoles("admin")
@RequestMapping(value = "/username/{name}",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultUtil<?> getUsername(@PathVariable("name") String name){
return ResultUtil.resultOK(userSerivce.findByName(name));
}
}
3.统一异常处理中心
@ControllerAdvice
public abstract class BaseController implements ResponseBodyAdvice<Object> {
@ExceptionHandler(RuntimeException.class)
public ResultUtil<?> runtime(RuntimeException exception) {
return ResultUtil.resultErr(exception.getMessage());
}
@ExceptionHandler(AuthenticationException.class)
public ResultUtil<?> shiroException(AuthenticationException e) {
if(e instanceof UnknownAccountException){
return ResultUtil.resultErr("用户不存在");
}else if(e instanceof IncorrectCredentialsException){
return ResultUtil.resultErr("密码错误");
}else if(e instanceof ExcessiveAttemptsException){
return ResultUtil.resultErr("认证次数超过限制,请稍后重试");
}
return ResultUtil.resultErr();
}
@ExceptionHandler(BindException.class)
public ResultUtil<?> bind(BindException exception) {
System.out.println("BindException.class");
// String message = exception.getAllErrors().stream().filter(x -> x instanceof FieldError)
// .map(x -> ((FieldError) x).getDefaultMessage()).reduce((x, y) -> x + y).get();
return ResultUtil.resultErr(exception.getFieldError().getDefaultMessage());
}
@ExceptionHandler(ValidationException.class)
public ResultUtil<?> validation(ValidationException exception) {
return ResultUtil.resultErr(exception.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultUtil<?> exceptionHandler(MethodArgumentNotValidException exception) {
BindingResult binding = exception.getBindingResult();
return ResultUtil.resultErr(binding.getFieldError().getDefaultMessage());
}
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) serverHttpRequest;
ServletServerHttpResponse serverResponse = (ServletServerHttpResponse) serverHttpResponse;
if (serverRequest == null || serverResponse == null || serverRequest.getServletRequest() == null
|| serverResponse.getServletResponse() == null) {
return o;
}
HttpServletRequest request = serverRequest.getServletRequest();
HttpServletResponse response = serverResponse.getServletResponse();
String originHeader = "Access-Control-Allow-Origin";
if (!response.containsHeader(originHeader)) {
String origin = request.getHeader("Origin");
if (origin == null) {
String referer = request.getHeader("Referer");
if (referer != null)
origin = referer.substring(0, referer.indexOf("/", 7));
}
response.setHeader("Access-Control-Allow-Origin", origin);
}
String allowHeaders = "Access-Control-Allow-Headers";
if (!response.containsHeader(allowHeaders))
response.setHeader(allowHeaders, request.getHeader(allowHeaders));
String allowMethods = "Access-Control-Allow-Methods";
if (!response.containsHeader(allowMethods))
response.setHeader(allowMethods, "GET,POST,OPTIONS,HEAD");
String exposeHeaders = "access-control-expose-headers";
if (!response.containsHeader(exposeHeaders))
response.setHeader(exposeHeaders, "x-auth-token");
return o;
}
}
最后贴上用到的maven依赖包
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.0</version>
</dependency>
<!-- jsonwebtoken -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!--swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-web</artifactId>
<version>1.1.4.RELEASE</version>
</dependency>