rest架构+跨域访问+JWT校验

非常感谢OAuth 2.0技术学习 https://www.itkc8.com

 

一套基于前后端分离架构的企业级的商户网站。为什么要采用前后端分离技术,很简单,目的是为了让后端人员专注做服务接口设计,前端人员专注用户体验设计,不像ERP系统那样禁锢与一贯的页面风格。
项目具体采用以下技术:
服务框架: jersey+mybaties     这个框架一般用的不多,但是作为rest框架而言,与SPRING只是大同小异,但是代码的规范性更强,因为是纯粹的接口框架。
登录缓存控制: JWT           JWT曾和SESSION有过不少争议。session的原理在于由服务端保存用户的sessionid,弊端就是会占用服务器大量内存,所以在大型项目当中会借用缓存工具进行存储。JWT的方式是将用户状态分散到了各个客户端,这样减轻了服务器的压力,也可不必使用缓存来处理,因为JWT的原理是通过将用户信息进行base64编码与加密签名来识别用户身份,当然JWT当中也允许加入用户的其他身份或者角色信息。具体JWT原理各位有兴趣可以去百度。

跨域访问机制:CORS       在解决跨域问题上,遇到了很大的坑,都是浏览器的同源策略害的,也是打算这次发帖的一个重要原因。
        先来分析一下跨域请求的一些机制:目前跨域请求大概有这么几种,个人觉得利弊如下:
       1、JSONP   这个方式对于我个人而言,确实没有一点P用, 客户端都是AJAX的POST请求,然后JSONP只支持GET请求方式,所以放弃使用
        2、iframe    很久以前做前端的时候,友人就告诫我能不用iframe的时候尽量少用。毕竟商户端网站后期的改造还是比较复杂,不排除会出现什么其他的坑。
       3、proxy代理   曾考虑在跨域无法访问的情况下,做一个springMvc工程作为代理跳转,不过这样做,要同时维护两个项目,在成本上不到万不得已不提倡。
       4、cors        最终选择这种方式,是因为配置上比较简单,而网上很多帖子都是通过cors实现跨域功能,但在实际调试过程中也踩过不少坑。后面慢慢介绍。
先说坑,关键字:
1、跨域功能在服务器上无法实现(本地正常)
2、nginx配置自定义header过滤(本地正常)
3、登录过滤器问题
4、jersey文件上传带参数获取

下面我分三点把项目情况描述一下:
一、JWT用户校验
     机制是这样,用户第一次登陆系统,根据用户相关信息,生成一串BASE64编码作为用户token,返回给客户端,客户端每次请求将这个token添加到request 请求头当中,系统过滤器通过对token的校验来验证用户是否合法。这里面存在两个问题:1、用户注销系统如何操作   2、token在请求头当中如何传输。直接看代码:
      (一)、jar包引用:
        <dependency>
              <groupId>io.jsonwebtoken</groupId>
              <artifactId>jjwt</artifactId>
              <version>0.6.0</version>
        </dependency>
      (二)、登录方法:

 

@POST
    @Path("/loginUser")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response loginUser(String resquestJsonBody,@Context HttpServletRequest request)
    {
        logger.info(String.format("Request IP--%s;requestJsonBody--%s", IpUtils.getIpAddr(request), resquestJsonBody));
        ZyLoginResponseVo zyLoginResponseVo = new ZyLoginResponseVo();
        String jsonRequestStr = RequestUtils.str2Json(resquestJsonBody);
        ZyLoginRequestVo zyLoginRequestVo = JSONObject.parseObject(jsonRequestStr, ZyLoginRequestVo.class);
        Map<String,Object> loginResult = zyLoginApiService.loginByUserName(zyLoginRequestVo);
        int code = Integer.parseInt(String.valueOf(loginResult.get("loginCode")));
        if (loginResult.get("loginCode").equals(Constants.AUTH_RESULT_SUCCESS))
        {
                //查询用户信息
               ZyUserDto resultDto= zyLoginApiService.findUserByName(zyLoginRequestVo.getUser_name());
               if(null == resultDto){
                   //用户不存在
                zyLoginResponseVo.setCode(code);
                zyLoginResponseVo.setDesc("User is not exists!!");
                logger.info("The responseJsonObject:" + JSONObject.toJSONString(zyLoginResponseVo));
                return Response.status(200).entity(JSONObject.toJSONString(zyLoginResponseVo)).type(new MediaType(CommonStr.APPLICATION, CommonStr.JSON, CommonStr.UTF8)).build();
               }
               //组装缓存数据
               String userName = String.valueOf(loginResult.get("userName"));
               String mobilePhone = String.valueOf(loginResult.get("mobilePhone"));
               Map<String,Object> claims = new HashMap<String,Object>();
               claims.put("acessToken", loginResult.get("accessToken"));
               claims.put("companyname", resultDto.getCompanyname());
               if(StringUtils.isEmpty(userName)){
               claims.put("name", resultDto.getUsername());
               }else{
                   claims.put("name", userName);
               }
               if(StringUtils.isEmpty(mobilePhone)){
                   claims.put("phone", resultDto.getPhone());
               }else{
                   claims.put("phone", mobilePhone);
               }
               claims.put("status", resultDto.getStatus());
               claims.put("companykey", resultDto.getCompanykey());
               claims.put("companyid", resultDto.getCompanyid());
               claims.put("id", resultDto.getId());
            // 设置这个token的生命时间
            Date expiry = getExpiryDate(30 * 24 * 60);//30天的有效日期
            // 使用Token工具类得到token,生成的策略是利用用户的姓名,到期时间,和私钥
            // 使用Key key =MacProvider.generateKey(SignatureAlgorithm.HS512);
            // HS512签名算法,必须保存生成的这个key到硬盘上,不然下次会出错,因为是hash算法,所以会变
            String userToken = TokenUtil.getJWTString(zyLoginRequestVo.getUser_name(), expiry,KeyUtil.getKey(context),resultDto.getCompanyid(),claims);
            logger.info("login Success, Token is:" + userToken+"; user is :"+userName);
            System.err.println("token is :"+userToken);
            zyLoginResponseVo.setCode(code);
            zyLoginResponseVo.createInstanceData().setToken(userToken);
            zyLoginResponseVo.setDesc("登录成功!");
        }else{
            String desc = ResultCodeDescUtil.getResultDesc(code);
            zyLoginResponseVo.setCode(code);
            zyLoginResponseVo.setDesc(desc);
        }
        logger.info("The responseJsonObject:" + JSONObject.toJSONString(zyLoginResponseVo));
        return Response.status(200).entity(JSONObject.toJSONString(zyLoginResponseVo)).type(new MediaType(CommonStr.APPLICATION, CommonStr.JSON, CommonStr.UTF8)).build();
    }


(一)、TOKEN 工具类
包含创建token,获取token附带信息。这里是把key文件保存在了项目当中,这个key文件只能生成一次,用户验证是通过这个key文件来处理,实际上是一串序列化的字符串。也可以改造成放入到数据库当中。

 

 

 

 

package ichano.developer.util;/**
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.Key;
import java.util.Date;
import java.util.Map;
import javax.annotation.security.PermitAll;
/** 
* @ClassName: TokenUtil 
* @Description: TODO(token管理工具类) 
* @author lizhijun
* @date 2016年8月11日 下午12:57:44 
*  
*/
@PermitAll
public class TokenUtil {
    public static String getJWTString(String tel,Date expires,Key key,String commpanyId,Map<String,Object> claims){
        if (tel == null) {
            throw new NullPointerException("null username is illegal");
        }
        if (expires == null) {
            throw new NullPointerException("null expires is illegal");
        }
        if (key == null) {
            throw new NullPointerException("null key is illegal");
        }
        SignatureAlgorithm signatureAlgorithm =SignatureAlgorithm.HS256;
        String jwtString = Jwts.builder()
                .setIssuer("Jersey-Security-Basic")
                .setSubject(tel)
                .setAudience("user")
                .setExpiration(expires)
                .setClaims(claims)
                .setIssuedAt(new Date())
                .setId(commpanyId)
                .signWith(signatureAlgorithm,key)
                .compact();
        return jwtString;
    }
    public static boolean isValid(String token, Key key) {
        try {
            Jwts.parser().setSigningKey(key).parseClaimsJws(token.trim());
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    public static String getName(String jwsToken, Key key) {
        if (isValid(jwsToken, key)) {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key).parseClaimsJws(jwsToken);
            String name = String.valueOf(claimsJws.getBody().get("name"));
            return name;
        }
        return null;
    }
    public static String[] getRoles(String jwsToken, Key key) {
        if (isValid(jwsToken, key)) {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key).parseClaimsJws(jwsToken);
            return claimsJws.getBody().getAudience().split(",");
        }
        return new String[]{};
    }
    public static int getVersion(String jwsToken, Key key) {
        if (isValid(jwsToken, key)) {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key).parseClaimsJws(jwsToken);
            return Integer.parseInt(claimsJws.getBody().getId());
        }
        return -1;
    }
    /** 
    * @Title: getCompanyId 
    * @Description: TODO(获取企业ID) 
    * @param @param jwsToken
    * @param @param key
    * @param @return    设定文件 
    * @return String    返回类型 
    * @throws 
    */
    public static String getCompanyId(String jwsToken, Key key) {
        if (isValid(jwsToken, key)) {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key).parseClaimsJws(jwsToken);
            String companyid = String.valueOf(claimsJws.getBody().get("id"));
          return companyid;
        }
        return null;
    }
    /** 
    * @Title: setAcccessToken 
    * @Description: TODO(存放鉴权中心token) 
    * @param @param accessToken
    * @param @param key
    * @param @return    设定文件 
    * @return String    返回类型 
    * @throws 
    */
    public static void setAcccessToken(String authToken, Key key,String accessToken) {
        if (isValid(authToken, key)) {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key).parseClaimsJws(authToken);
            claimsJws.getBody().put("acessToken", accessToken);
        }
    }
    /** 
    * @Title: getCompanyId 
    * @Description: TODO(获取鉴权中心Token) 
    * @param @param jwsToken
    * @param @param key
    * @param @return    设定文件 
    * @return String    返回类型 
    * @throws 
    */
    public static String getAccessToken(String jwsToken, Key key) {
        if (isValid(jwsToken, key)) {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key).parseClaimsJws(jwsToken);
            return claimsJws.getBody().getSubject();
        }
        return null;
    }
}

 

 

 

 

 

(四)、过滤器处理
在过滤器当中需要添加一些不需要进行token校验的请求路径,可以直接访问。 在这里没有角色权限的校验,有需要的可以自行设计。

 

package ichano.developer.sys.filter;/**
import ichano.developer.biz.service.ZyLoginService;
import ichano.developer.dto.ZyUserDto;
import ichano.developer.util.KeyUtil;
import ichano.developer.util.TokenUtil;
import java.io.IOException;
import java.security.Key;
import javax.annotation.Priority;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.ws.rs.Priorities;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.beans.factory.annotation.Autowired;
/** 
* @ClassName: JWTSecurityFilter 
* @Description: TODO(权限验证过滤器) 
* @author lizhijun
* @date 2016年8月11日 下午1:18:52 
*  
*/
@Provider
@Priority(Priorities.AUTHENTICATION)//优先级最高
//实现该拦截器借口
//@Provider可以自动注册
@PreMatching         //这个必须添加,否则无法拦截请求
public class JWTSecurityFilter implements ContainerRequestFilter{
    final static Logger logger = LogManager.getLogger(JWTSecurityFilter.class.getName());
    @Autowired
    ZyLoginService zyLoginService;
 
    @Context
    ServletContext context;
 
    @Inject
    javax.inject.Provider<UriInfo> uriInfo;
    public static String extractJwtTokenFromAuthorizationHeader(String auth) {
        //Replacing "Bearer Token" to "Token" directly
        return auth.replaceFirst("[B|b][E|e][A|a][R|r][E|e][R|r] ", "").replace(" ", "");
    }
  //重写验证过滤器
    @Override
    public void filter(ContainerRequestContext containerRequestContext) throws IOException {
        //获取本地的私钥
        Key key= KeyUtil.getKey(context);
        //得到访问的方法 例如GET,POST
        String method = containerRequestContext.getMethod().toLowerCase();
        //预校验请求处理
        if(method.equals("options")){
            containerRequestContext.setSecurityContext(new SecurityContextAuthorizer(uriInfo,new AuthorPricinple("pass"), new String[]{"pass"}));
            return;
        }
        //得到访问路径
        String path = ((ContainerRequest) containerRequestContext).getPath(true).toLowerCase();
 
        System.err.println("authorizationHeader path is :"+path);
        //不需要验证,post验证过滤,注册过滤。
        if ("post".equals(method) && "developer/loginuser".equals(path)
                || "developer/registeruser".equals(path)
                || "developer/sendverifcode".equals(path)
                || "developer/updatepwd".equals(path) 
                ||"license/uploadfilecheck".equals(path)
                ||"product/uploadproductimg".equals(path)) {
            containerRequestContext.setSecurityContext(new SecurityContextAuthorizer(uriInfo,new AuthorPricinple("pass"), new String[]{"pass"}));
            return;
        }
        //获取头信息中的token
        MultivaluedMap<String, String> testToken = ((ContainerRequest) containerRequestContext).getHeaders();
        String authorizationHeader = ((ContainerRequest) containerRequestContext).getHeaderString("auth_token");
        //如果token为空抛出
        if (authorizationHeader == null) {
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);//抛出未认证的错误
        }
        //把Bear Token换成Token
        String strToken=extractJwtTokenFromAuthorizationHeader(authorizationHeader);
        if (TokenUtil.isValid(strToken,key)){
            String name=TokenUtil.getName(strToken,key);//反解出Name
//            String[] roles=TokenUtil.getRoles(strToken,key);//反解出角色
            if(name !=null){
                ZyUserDto user=zyLoginService.findUserByName(name);
                if(user!=null){
                    containerRequestContext.setSecurityContext(new SecurityContextAuthorizer(uriInfo,new AuthorPricinple(name), new String[]{"user"}));
                    return;
                }
                else{
                    logger.info("User not found " + name);
                }
            }
            else {
                logger.info("name, roles or version missing from token");
            }
        }
        else {
            logger.info("token is invalid");
        }
        throw new WebApplicationException(Response.Status.UNAUTHORIZED);
    }
}


(五)、前端请求代码
采用ajax post请求方式。
 // 发送登陆请求

 

 

 

 

$.ajax({
                url: "http://192.168.0.55:8080/developer/developer/loginUser",
                type: "POST",
                dataType: "json",
                contentType: "application/json",      <span style="color: #FF0000;">    //注意:如果有post data参数的时候,必须加这段,否则请求获取不到参数</span>      
                data: {
                    user_name: userName,
                    password: userPwd,
                    type: type
                },
                success: function(data) {
                    console.log(data);
                    if (data.code == 1000) {
                        $.cookie('token', data.data.token);
                        console.log(1);
                        parent.location.reload();
                    } else if (data.code == 2006) {
                        layer.msg("用户名密码错误");
                    } else {
                        layer.msg("登陆异常");
                    }
                }
            });


//访问接口请求

 

 

 

 

 $.ajax({
            url: "http://192.168.0.181:9102/developer/developer/checkLogin",
            type: 'POST',
            dataType: 'json',
            beforeSend: function(request) {                       //添加请求响应头中的自定义token
                request.setRequestHeader("auth_token", token);
            },
            success: function(data) {
                if (data.code == 1000) {
                    var html = [];
                    html.push(Mustache.render(userNameTemp, data.data));
                    $userNameCon.html(html.join(''));
                } else {
                    window.location.href = "index.html"
                }
            }
        })

二、CORS跨域访问     
        使用cors进行跨域配置其实很简单,只需要引用jar包,然后添加过滤器即可。但是有些细节还是要注意。
       (一)、jar包引用
         <dependency>
            <groupId>com.thetransactioncompany</groupId>
            <artifactId>cors-filter</artifactId>
            <version>2.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.thetransactioncompany/java-property-utils -->
        <dependency>
            <groupId>com.thetransactioncompany</groupId>
            <artifactId>java-property-utils</artifactId>
            <version>1.9.1</version>
        </dependency>
(二)、过滤器实现
         web.xml配置:

 

 

 <filter>
    <filter-name>cros</filter-name>
    <filter-class>ichano.developer.sys.filter.CorsFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>cros</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

过滤器中可以配置允许访问的请求方,允许访问的请求方式以及允许通过的请求头信息

 

 

package ichano.developer.sys.filter;/**
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;
/** 
* @ClassName: CorsFilter 
* @Description: TODO(设置其他IP地址的机器可以直接访问本项目Url--工具filter) 
* @author lizhijun
* @date 2016年8月15日 下午2:25:25 
*  
*/
public class CorsFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");      //为安全起见,可配置允许访问的请求方地址。这里配置成*号,是允许所有访问。
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");        //为安全起见,也可配置成只允许POST请求
        response.addHeader("Access-Control-Allow-Headers", "Content-Type,auth_token");      //这里要注意,auth_token是我自定义的请求头当中带的token,在这里必须添加,否则你永远获取不到。
        response.addHeader("Access-Control-Max-Age", "1800");//30 min
        filterChain.doFilter(request, response);
    }
}


这里处理了三个坑,
一是在本地调试的时候可以跨域访问,但是部署到服务器之后,访问失败。解决方法:请求地址后面加上端口号就可以访问。  这个问题就需要在nignx里面进行端口配置。
二是CROS这种传输方式传输的数据到后端接收已不是JSON格式,而是类似于XXX=123&FFFF=384这样的格式,需要对所有请求的入参进行一下转换成json格式。
三是请求头中的自定义字段auth_token在服务器上接收不到,这里需要对ngnix进行配置,允许自定义属性的header配置。
[b]

 

 

三、补充点   jersey框架文件上传方式,包含带有参数上传[/b]
       通过form表单提交方式进行图片上传
     (一)、页面

 

<div class="header" style="background-color:#14C2FF;width:400px,height:800px; border:1px red solid;">
            <form action="http://localhost:8080/ichanoDeveloper/product/uploadProductImg" method="post" enctype="multipart/form-data">  
                <p>  
                                     <input type="file"  class="sys_input"     name ="productLogo"  id="productLogo"   />
                        剩productId:<input type="text" name="productId" value="20" id="productId"/><br />  
                </p>  
                <input type="submit" value="上传" />  
          </form> 
        </div>

(二)处理代码

 

 

         /** 
    * @Title: uploadFileCheck 
    * @Description: TODO(这里用一句话描述这个方法的作用) 
    * @param @param fileInputStream
    * @param @param disposition
    * @param @param request
    * @param @return    设定文件 
    * @return String    返回类型 
    * @throws 
    */
    @POST
    @Path("/uploadFileCheck")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.TEXT_PLAIN)
    public Response uploadTemp( @FormDataParam("updateLicense") final InputStream uploadedInputStream,
            @FormDataParam("updateLicense") final FormDataContentDisposition fileDetail,
            @FormDataParam( "surplusCount") final List<FormDataBodyPart> keywordObjs,@Context HttpServletRequest request ) {
        String fileName = Calendar.getInstance().getTimeInMillis()+ fileDetail.getFileName();  
        ZyUploadLicenseFileResponseVo zyUploadLicenseFileResponseVo = new ZyUploadLicenseFileResponseVo();
        ZyUploadLicenseFileRequestVo zyUploadLicenseFileRequestVo = new ZyUploadLicenseFileRequestVo();
        if (keywordObjs != null && ! keywordObjs.isEmpty()) {
           for (FormDataBodyPart keywordObj : keywordObjs) {
               String keyName = keywordObj.getName();
               if("surplusCount".equals(keyName)){
                   zyUploadLicenseFileRequestVo.setSurplusCount(keywordObj.getValueAs(String.class));
                   break;
               }
           }
        }
        String accessToken = TokenUtil.getAccessToken(request.getHeader("auth_token"),KeyUtil.getKey(context));
        Key key= KeyUtil.getKey(context);
        if (TokenUtil.isValid(accessToken,key)){
            zyUploadLicenseFileRequestVo.setInputStream(uploadedInputStream);
            zyUploadLicenseFileRequestVo.setFileName(fileName);
            zyUploadLicenseFileResponseVo= zyLicenseApiService.uploadBatchExcel(zyUploadLicenseFileRequestVo);
        }else{
            zyUploadLicenseFileResponseVo.setCode(Constants.AUTH_RESULT_FILE_SESSIONOUT);
            zyUploadLicenseFileResponseVo.setDesc("Session is out!");
        }
        logger.info("The responseJsonObject:" + JSONObject.toJSONString(zyUploadLicenseFileResponseVo));
        return Response.status(200).entity(JSONObject.toJSONString(zyUploadLicenseFileResponseVo)).type(new MediaType(CommonStr.APPLICATION, CommonStr.JSON, CommonStr.UTF8)).build();
    }
 
 
 
@Override
    public ZyUploadLicenseFileResponseVo uploadBatchExcel(ZyUploadLicenseFileRequestVo zyUploadLicenseFileRequestVo) {
        ZyUploadLicenseFileResponseVo zyUploadLicenseFileResponseVo = new ZyUploadLicenseFileResponseVo();
//  参数有误
        if (!zyUploadLicenseFileRequestVo.isValid()) {
                logger.error("The argument is null!");
                zyUploadLicenseFileResponseVo.setCode(Constants.AUTH_RESULT_FILE_2001);
                zyUploadLicenseFileResponseVo.setDesc("The argument is invalid!!");
                return zyUploadLicenseFileResponseVo;
        }
        String fileName = zyUploadLicenseFileRequestVo.getFileName();
        List licenseInfo = new ArrayList<String>();
        if(!fileName.contains("xls")){
            logger.error("The fileName[{}]  is error!", fileName);
            zyUploadLicenseFileResponseVo.setCode(Constants.UPLOAD_FAILE_9002);
            zyUploadLicenseFileResponseVo.setDesc("The file fomart is faile!!");
            return zyUploadLicenseFileResponseVo;
        }
        try {
            workbook = new XSSFWorkbook(zyUploadLicenseFileRequestVo.getInputStream());
            XSSFSheet sheet = workbook.getSheetAt(0);   //获取第一个sheet
            int rows = sheet.getPhysicalNumberOfRows();//行数
            int cols = sheet.getRow(1).getPhysicalNumberOfCells();//列数
            if(cols != 2){
                logger.error("The file fomart is faile!");
                zyUploadLicenseFileResponseVo.setCode(Constants.UPLOAD_FAILE_9002);
                zyUploadLicenseFileResponseVo.setDesc("文件格式错误!!");
                return zyUploadLicenseFileResponseVo;
            }
            //校验上传的excel是否为标准模版
            if(rows>0){
                //有数据
                for(int i=3;i<rows;i++){
                    //从第四行开始检索
                    String tempLicense = String.valueOf(sheet.getRow(i).getCell(1));
                    if(tempLicense.length()<=32){
                        licenseInfo.add(tempLicense);
                    }
                }
            }
            int surplusLicenseInt = Integer.parseInt(zyUploadLicenseFileRequestVo.getSurplusCount());
            zyUploadLicenseFileResponseVo.setCode(Constants.AUTH_RESULT_SUCCESS);
            zyUploadLicenseFileResponseVo.setDesc("Upload File Success!");
            zyUploadLicenseFileResponseVo.createInstanceData().setLicenseList(licenseInfo);
            return zyUploadLicenseFileResponseVo;
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("解析上传文件失败!");
            zyUploadLicenseFileResponseVo.setCode(Constants.UPLOAD_FAILE_9002);
            zyUploadLicenseFileResponseVo.setDesc("解析上传文件失败!");
            return zyUploadLicenseFileResponseVo;
        } 
    }

 

非常感谢OAuth 2.0技术学习 https://www.itkc8.com

 

 

 

       

 

 

 

 

 

 

 

 


 

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是Spring Boot 3 + Spring Security 6 + JWT的项目配置步骤: 1. 添加Spring Security和JWT的依赖 在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 2. 配置JWT 在application.yml或者application.properties文件中添加JWT的配置信息: ``` jwt: secret: yourSecretKey expiration: 604800000 # 7 days ``` 3. 配置Spring Security 创建一个继承自WebSecurityConfigurerAdapter的配置类,并添加以下代码: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsService customUserDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/auth/**") .permitAll() .anyRequest() .authenticated(); http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } } ``` 其中,CustomUserDetailsService是自定义的用户认证服务,JwtAuthenticationFilter是自定义的JWT认证过滤器。 4. 编写JWT认证过滤器 创建一个继承自OncePerRequestFilter的JwtAuthenticationFilter,并添加以下代码: ```java public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private JwtTokenProvider jwtTokenProvider; @Autowired private CustomUserDetailsService customUserDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { String token = jwtTokenProvider.resolveToken(request); if (token != null && jwtTokenProvider.validateToken(token)) { Authentication authentication = jwtTokenProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (JwtAuthenticationException ex) { SecurityContextHolder.clearContext(); response.sendError(ex.getHttpStatus().value(), ex.getMessage()); return; } filterChain.doFilter(request, response); } } ``` 其中,JwtTokenProvider是自定义的JWT Token提供器。在这个过滤器中,我们通过JWT Token提供器解析请求中的Token,并将用户认证信息存储在SecurityContextHolder中。 5. 编写JWT Token提供器 创建一个JwtTokenProvider类,并添加以下代码: ```java @Service public class JwtTokenProvider { @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; public String createToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + expiration)) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(secret).parseClaimsJws(token); return true; } catch (JwtException | IllegalArgumentException ex) { throw new JwtAuthenticationException("Expired or invalid JWT token", HttpStatus.INTERNAL_SERVER_ERROR); } } public Authentication getAuthentication(String token) { UserDetails userDetails = customUserDetailsService.loadUserByUsername(getUsername(token)); return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities()); } public String getUsername(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody() .getSubject(); } public String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } } ``` 其中,UserDetails是Spring Security提供的用户认证信息对象,CustomUserDetailsService是自定义的用户认证服务。 在这个类中,我们使用JJWT库来创建和解析JWT Token,并在getAuthentication方法中从Token中获取用户认证信息,并将其封装成Spring Security的Authentication对象。 以上就是Spring Boot 3 + Spring Security 6 + JWT的项目配置步骤。希望能够帮到您!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值