1.不保存Session拦截策略 (生成 加密 token 可保存密码)
登录Controller
package com.xiaoben.nuxt.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xiaoben.nuxt.entity.CustomerSystemUser;
import com.xiaoben.nuxt.service.CustomerSystemUserServices;
import com.xiaoben.nuxt.vo.AsyncJson;
import com.xiaoben.nuxt.vo.LoginFormVo;
@RestController
@RequestMapping("/lift/passport/")
public class PassportController {
@Autowired
private CustomerSystemUserServices sysUserServices;
@PostMapping("login")
public AsyncJson login(@RequestBody LoginFormVo loginFormVo){
return sysUserServices.loginSystem(loginFormVo);
}
}
登录Services
package com.xiaoben.nuxt.service;
import com.xiaoben.nuxt.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaoben.nuxt.entity.CustomerSystemUser;
import com.xiaoben.nuxt.mapper.CustomerSystemUserMapper;
import com.xiaoben.nuxt.utils.JwtUtil;
import javax.annotation.Resource;
import java.util.List;
@Service
public class CustomerSystemUserServices extends ServiceImpl<CustomerSystemUserMapper,CustomerSystemUser> {
@Autowired
private JwtUtil jwtUtil;
@Resource
private CustomerSystemUserMapper customerSystemUserMapper;
public AsyncJson loginSystem(LoginFormVo loginFormVo) {
CustomerSystemUser user = baseMapper.getSysUserByName(loginFormVo.getUsername());
if (user == null){
return AsyncJson.error("此用户不存在");
}
if (!user.getPassword().equals(loginFormVo.getPassword())){
return AsyncJson.error("密码输入错误");
}
String token = jwtUtil.createJwtNoEndTime(user.getId().toString(), user.getName(), user.getPassword());
user.setPassword(null);
user.getTransients().put("token",token);
return AsyncJson.success("success",user);
}
}
jwtUtil 工具类
package com.xiaoben.nuxt.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Date;
@ConfigurationProperties("jwt.config")
public class JwtUtil {
private String key ;
private long ttl ;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public long getTtl() {
return ttl;
}
public void setTtl(long ttl) {
this.ttl = ttl;
}
/**
* 生成JWT
*
* @param id
* @param subject
* @return
*/
public String createJWT(String id, String subject, String roles) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
JwtBuilder builder = Jwts.builder().setId(id)
.setSubject(subject)
.setIssuedAt(now)
.signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
if (ttl > 0) {
builder.setExpiration( new Date( nowMillis + ttl));
}
return builder.compact();
}
public String createJwtNoEndTime(String id, String subject, String roles) {
JwtBuilder builder = Jwts.builder().setId(id)
.setSubject(subject)
.signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
return builder.compact();
}
/**
* 解析JWT
* @param jwtStr
* @return
*/
public Claims parseJWT(String jwtStr){
return Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(jwtStr)
.getBody();
}
}
配置文件jwt配置
jwt:
config:
key: 8vZnRPn0ak2gJbo2jwe4GDGCZoa1JCzo5BQtLD8HqlrvYgqSqq #更新的jwt按规范要求256bit长度
management:
endpoints:
web:
exposure:
include: "*"
拦截器
package com.xiaoben.nuxt.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.execchain.TunnelRefusedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.xiaoben.nuxt.utils.JwtUtil;
import io.jsonwebtoken.Claims;
/*
* 拦截器
*/
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
private JwtUtil jwtUtil;
/*
* 在进入控制层之前进行拦截处理
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//放行OPTIONS请求
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
return true;
}
//从浏览器头信息获取token
String token = request.getHeader("token");
System.out.println(token);
//判断token是否为空
if(StringUtils.isNotBlank(token)) {
System.out.println("*************1********************");
try {
Claims claims = jwtUtil.parseJWT(token);
String subject = claims.getId();
if (StringUtils.isNotBlank(subject)) {
request.setAttribute("user_id", subject);
return true;
}
} catch (Exception e) {
throw new RuntimeException("令牌有误!");
}
}
return false;
}
}
拦截器配置类
package com.xiaoben.nuxt.config;
import java.io.File;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import com.xiaoben.nuxt.filter.JwtInterceptor;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/*
* 配置类
*/
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Value("${file.staticAccessPath}")
private String staticAccessPath;
@Value("${file.uploadFolder}")
private String uploadFolder;
@Autowired
private JwtInterceptor jwtInterceptor;//jwt拦截器
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/templates/");
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler(staticAccessPath).addResourceLocations("file:" + uploadFolder);
}
/*
* addInterceptors:自定义生命周期拦截器的配置
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addInterceptor方法是注册一个生命周期拦截器,
// addPathPatterns方法是拦截的url地址,
// excludePathPatterns是排除那些地址不拦截,order方法是拦截顺序,就是拦截器执行链的执行顺序,值越大,拦截就越靠后
ArrayList<String> list = new ArrayList<>();
list.add("/lift/passport/login");
list.add("/lift/passport/logout");
list.add("/lift/App/*");
/*
* 对根目录和静态文件不需要进行拦截,如果对根目录(即登录页面)进行拦截,将会导致循环重定向
* (1)addInterceptor(jwtInterceptor)---注入自定义的拦截器
* (2)excludePathPatterns(list)---排除的拦截
* (3)addPathPatterns("/app/**", "/api/**") 拦截的url地址,app:手机端 , api后台接口
*/
registry.addInterceptor(jwtInterceptor).excludePathPatterns(list).addPathPatterns("/lift/**");
}
}
1.简单保存Session拦截策略 (验证码请求验证可以忽略)(没生成 token后期可以加)(AuthUser 类要自己创建)
登录Controller
package com.xiaoben.nuxt.ctrl.login;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.xiaoben.nuxt.service.SystemUserService;
import com.xiaoben.nuxt.vo.AsyncJson;
import com.xiaoben.nuxt.vo.LoginForm;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
@RequestMapping("/api/passport")
public class LoginController {
@Autowired
private SystemUserService userService;
/**
*
* 不使用 Session 的 SpringBoot kaptcha 图片验证码校验
*/
/**
* 得到登陆验证码
* @param response
* @throws IOException
*/
@GetMapping("getCode")
public void getCode(HttpServletResponse response, HttpServletRequest request) throws IOException{
//定义图形验证码的长和宽
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(116, 36,4,5);
request.getSession(true).setAttribute("captcha", lineCaptcha.getCode());
ServletOutputStream outputStream = response.getOutputStream();
lineCaptcha.write(outputStream);
outputStream.close();
}
@PostMapping("login")
public Object login(@RequestBody LoginForm form, HttpServletRequest request){
String code = (String) request.getSession(true).getAttribute("captcha");
if (!StringUtils.equals(form.getCheckCode(),code)){
return AsyncJson.error(40000,"验证码不正确!");
}
AsyncJson json = userService.loginSystem(form, request.getSession());
return json;
}
@GetMapping("logout")
public Object logout(HttpServletRequest request) {
request.getSession().invalidate();
return AsyncJson.success("退出成功");
}
}
package com.xiaoben.nuxt.service;
import java.util.HashMap;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaoben.common.security.AuthUser;
import com.xiaoben.nuxt.comon.Const;
import com.xiaoben.nuxt.entity.SystemUser;
import com.xiaoben.nuxt.mapper.SystemMenuMapper;
import com.xiaoben.nuxt.mapper.SystemUserMapper;
import com.xiaoben.nuxt.utils.JwtUtil;
import com.xiaoben.nuxt.utils.MD5;
import com.xiaoben.nuxt.vo.AsyncJson;
import com.xiaoben.nuxt.vo.LoginForm;
@Service
@Transactional
public class SystemUserService extends ServiceImpl<SystemUserMapper, SystemUser>{
@Resource
private SystemMenuMapper menuMapper;
public AsyncJson loginSystem(LoginForm form, HttpSession session) {
SystemUser su = baseMapper.findByCustNumber(form.getCustNumber());
AsyncJson e = this.check(su, form);
if(e != null) {
return e;
}
HashMap<String, Object> map = new HashMap<>();
map.put("su",su);
//SESSION 存储授权用户信息, 以及店铺信息
AuthUser au = new AuthUser(su.getName(), su.getId(), su.getName(), null);
au.setShopId(-1L); //上传附件时填为-1
session.setAttribute("user", au);
return AsyncJson.success("", map);
}
}
创建 拦截器
package com.xiaoben.nuxt.interceptor;
import com.alibaba.fastjson.JSON;
import com.xiaoben.nuxt.vo.AsyncJson;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
拦截器
* */
@Component
public class JwtInterceptor implements HandlerInterceptor {
/*
* 在进入控制层之前进行拦截处理*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//放行OPTIONS请求
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
return true;
}
//没有登录,不允许请求
if(request.getSession(true).getAttribute("user") == null) {
response.addHeader("Content-Type", "application/json;charset=utf-8");
response.getWriter().append(JSON.toJSONString(AsyncJson.error(601, "登录已过期,请重新登录")));
return false;
}
return true;
}
}
拦截器配置
package com.xiaoben.nuxt.config;
import com.xiaoben.nuxt.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
import java.util.ArrayList;
//@EnableWebMvc 这个加上去会bean冲突
/**
* 默认还是用springboot的配置,部分配置调整
* @author Administrator
*
*
*/
@Configuration
public class InterceptorConfig extends WebMvcAutoConfiguration implements WebMvcConfigurer {
@Value("${file.staticAccessPath}")
private String staticAccessPath;
@Resource(name="fileUploadPath")
private String uploadFolder;
@Autowired
private JwtInterceptor jwtInterceptor;//jwt拦截器
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(staticAccessPath).addResourceLocations("file:" + uploadFolder);
}
/*
* 、addInterceptors:自定义生命周期拦截器的配置*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addInterceptor方法是注册一个生命周期拦截器,
// addPathPatterns方法是拦截的url地址,
// excludePathPatterns是排除那些地址不拦截,order方法是拦截顺序,就是拦截器执行链的执行顺序,值越大,拦截就越靠后
ArrayList<String> list = new ArrayList<>();
list.add("/api/passport/**");
/*
* 对根目录和静态文件不需要进行拦截,如果对根目录(即登录页面)进行拦截,将会导致循环重定向
* (1)addInterceptor(jwtInterceptor)---注入自定义的拦截器
* (2)excludePathPatterns(list)---排除的拦截
* (3)addPathPatterns("/app/**", "/api/**") 拦截的url地址,app:手机端 , api后台接口
*/
registry.addInterceptor(jwtInterceptor).excludePathPatterns(list).addPathPatterns("/api/**");
}
}