前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小程序登录及token

小程序登录及token

作者头像
Remember_Ray
发布2020-10-29 11:15:19
4.2K0
发布2020-10-29 11:15:19
举报
文章被收录于专栏:Ray学习笔记

官方文档-服务端

目的

实现用户登录小程序,获取当前用户的信息,发送到后端服务器,并返回token。

设计思路

  1. 在页面加载完成时调用 onLoad
  2. 先检验本地缓存中是否有token,直接请求后端服务器,获取数据库用户信息;
  3. 如果没有token,调用 wx.login() ,获取到一个 code;
  4. 如果 openId 存在于数据库中,直接根据 openId 查询用户信息,返回用户信息和token;
  5. 如果 openId 不存在与数据库中,把 openId 存到数据库当中,相当于插入了新的 User 用户,返回用户信息和token
  6. 小程序获取到用户信息和token,将token缓存到本地中,如果发起新的请求,请求头携带token
  7. 后端接收到token后,验证token是否过期,如果没有过期则返回相应结果。

小程序

wxml

代码语言:javascript
复制
<!-- miniprogram/components/action/action.wxml -->
<form bindsubmit="bindSave">
  <view style='width:100%;padding-left:30rpx;font-size: 30rpx;margin-top:50rpx;'>
    1. 同意当前小程序授权登录;
    <button type="primary" open-type="getUserInfo" bindtap="doLogin">授权登录</button>
  </view>
  <view style='width:100%;padding-left:30rpx;font-size: 30rpx;margin-top:20rpx;'>
    2. 同意当前小程序获取我的个人信息;
    <button type="primary" open-type="getUserInfo" bindtap="doUserInfo">获取个人信息</button>
  </view>
</form>

js

代码语言:javascript
复制
// miniprogram/components/action/action.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  },

  /** 登录 */
  doLogin: function (callback = () => { }) {
    let that = this;
    wx.login({
      success: function (loginRes) {
        if (loginRes) {
          //获取用户信息
          wx.getUserInfo({
            withCredentials: true,//非必填  默认为true
            success: function (infoRes) {
              console.log(infoRes, '>>>');
              //请求服务端的登录接口
              wx.request({
                // url: 'http://127.0.0.1:8080/wx/user/wx505c137810163551/login',
                url: 'http://127.0.0.1:8078/app/wx/user/login',
                data: {
                  code: loginRes.code,//临时登录凭证
                  rawData: infoRes.rawData,//用户非敏感信息
                  signature: infoRes.signature,//签名
                  encryptedData: infoRes.encryptedData,//用户敏感信息
                  iv: infoRes.iv//解密算法的向量
                },
                success: function (res) {
                  console.log('login success');
                  console.log("res:", res)

                  // that.globalData.session = res.data;
                  // wx.setStorageSync('session', JSON.stringify(res.data.data));
                  // wx.setStorageSync('sessionKey', res.data.data.session.sessionKey);
                  // wx.setStorageSync('openid', res.data.data.session.openid);
                  wx.setStorageSync('token', res.data.data.token);
                  // console.log("sessionKey=" + res.data.data.session.sessionKey);
                  // console.log("openid=" + res.data.data.session.openid);
                  console.log("token=" + res.data.data.token);
                  // callback();

                },
                fail: function (error) {
                  //调用服务端登录接口失败
                  // that.showInfo('调用接口失败');
                  console.log(error);
                }
              });
            }
          });
        } else {

        }
      }
    });
  },



  /** 用户信息 */
  doUserInfo: function (callback = () => { }) {
    let that = this;
    wx.login({
      success: function (loginRes) {
        if (loginRes) {
          //获取用户信息
          wx.getUserInfo({
            withCredentials: true,//非必填  默认为true
            success: function (infoRes) {
              console.log(infoRes, '>>>');
              console.log("token: >> ", wx.getStorageSync('token'))
              //请求服务端的登录接口
              wx.request({
                // 带token信息
                header: {
                  token: wx.getStorageSync('token')
                },
                // url: 'http://127.0.0.1:8080/wx/user/wx505c137810163551/info',
                url: 'http://127.0.0.1:8078/app/wx/user/info',
                data: {
                  sessionKey: wx.getStorageSync('sessionKey'),
                  code: loginRes.code,//临时登录凭证
                  rawData: infoRes.rawData,//用户非敏感信息
                  signature: infoRes.signature,//签名
                  encryptedData: infoRes.encryptedData,//用户敏感信息
                  iv: infoRes.iv//解密算法的向量
                  // ,token: wx.getStorageSync('token')
                },
                success: function (res) {
                  console.log("res:", res)
                },
                fail: function (error) {
                  //调用服务端登录接口失败
                  // that.showInfo('调用接口失败');
                  console.log(error);
                }
              });
            }
          });
        } else {

        }
      }
    });
  }
})

Java 后端

pom

代码语言:javascript
复制
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-miniapp</artifactId>
    <version>3.9.0</version>
</dependency>

controller

代码语言:javascript
复制
package com.dfht.modules.wx.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.dfht.common.web.JwtUtils;
import com.dfht.modules.app.annotation.Login;
import com.dfht.modules.app.interceptor.AuthorizationInterceptor;
import com.dfht.modules.sys.entity.User;
import com.dfht.modules.sys.utils.UserUtils;
import com.dfht.modules.wx.common.AjaxResult;
import com.dfht.modules.wx.config.WxConfiguration;
import com.dfht.modules.wx.service.WxUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 微信小程序用户接口
 * @Author Ray
 * @Date 2020/10/19 10:07
 * @Version 1.0
 */
@RestController
@RequestMapping("${apiPath}/wx/user")
public class WxUserController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private WxUserService wxUserService;
    @Autowired
    private JwtUtils jwtUtils;

    @Value("${miniapp_appid}")
    private String appId;

    /**
     * 登陆接口
     * @param code 临时登录凭证
     * @param encryptedData 用户敏感信息
     * @param iv 解密算法的向量
     * @return
     */
    @RequestMapping("/login")
    public AjaxResult test(String code, String encryptedData, String iv) {

        Map<String, Object> result = new HashMap<>(5);

        try {
            // 获取微信用户信息
            final WxMaService wxService = WxConfiguration.getMaService(appId);
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
            //result.put("session", session);

            // 获取后台用户信息
            WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), encryptedData, iv);
            User user = wxUserService.getUserByWxMaUserInfo(userInfo);
            result.put("user", user);

            // 生成 token
            String token = jwtUtils.generateToken(user.getId());
            result.put("token", token);
            result.put("expire", jwtUtils.getExpire());

            logger.info("" + result);
            return AjaxResult.success(result);

        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error();
        }
    }


    /**
     * 获取用户信息接口
     */
    @GetMapping("/info")
    @Login
    public AjaxResult info(HttpServletRequest request) {
        // 从 request 中获取 userId
        String userId = (String) request.getAttribute(AuthorizationInterceptor.USER_KEY);
        User user = UserUtils.get(userId);
        return AjaxResult.success(user);

    }
}
代码语言:javascript
复制
package com.dfht.modules.wx.controller;

import cn.hutool.core.date.DateUtil;
import com.dfht.modules.app.annotation.Login;
import com.dfht.modules.app.interceptor.AuthorizationInterceptor;
import com.dfht.modules.sys.entity.User;
import com.dfht.modules.sys.utils.UserUtils;
import com.dfht.modules.wx.common.AjaxResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @Description: 微信小程序测试接口
 * 注意:头部或参数必须带token信息
 * @Author Ray
 * @Date 2020/10/19 10:07
 * @Version 1.0
 */
@RestController
@RequestMapping("${apiPath}/wx/test")
public class WxTestController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 必须传token
     */
    @RequestMapping("/token")
    @Login
    public AjaxResult token(HttpServletRequest request){
        logger.info("token()");
        return AjaxResult.success(DateUtil.now());
    }

    /**
     * 不用传token
     */
    @RequestMapping("/nonToken")
    public AjaxResult nonToken(HttpServletRequest request){
        logger.info("nonToken()");
        return AjaxResult.success(DateUtil.now());
    }
}

service

代码语言:javascript
复制
package com.dfht.modules.wx.service;

import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.dfht.common.utils.IdGen;
import com.dfht.common.utils.SpringContextHolder;
import com.dfht.modules.sys.dao.UserDao;
import com.dfht.modules.sys.entity.Role;
import com.dfht.modules.sys.entity.User;
import com.dfht.modules.sys.service.LogService;
import com.dfht.modules.sys.service.SystemService;
import com.dfht.modules.sys.utils.UserUtils;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: 微信小程序用户业务
 * @Author Ray
 * @Date 2020/10/19 11:10
 * @Version 1.0
 */
@Service
public class WxUserService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private SystemService systemService;

    public static final String wxDefaultPassword = "WxDefaultPassword";


    /**
     * 根据 openId 获取用户
     */
    public User getUserByWxMaUserInfo(WxMaUserInfo userInfo) {
        User user = new User();
        user.setOpenId(userInfo.getOpenId());
        user = userDao.getUserByWxOpenId(user);

        // 已注册
        if(user != null) {
            String id = user.getId();
            // 其他操作

            return user;
        }

        // 未注册
        // 则创建微信用户
        user = this.createWxUser(userInfo);

        return user;
    }


    /**
     * 创建微信用户
     */
    public User createWxUser(WxMaUserInfo userInfo) {

        User user = new User();

        List<String> roleIdLists = new ArrayList<>();
        // 假设数据库中已经存在这个角色
        Role role = UserUtils.getRoleByEnName("wxUser");
        roleIdLists.add(role.getId());
        user.setRoleIdList(roleIdLists);

        // 角色数据有效性验证,过滤不在授权内的角色
        List<Role> roleList = Lists.newArrayList();
        List<String> roleIdList = user.getRoleIdList();
        for (Role r : systemService.findAllRoleList()){
            if (roleIdList.contains(r.getId())){
                roleList.add(r);
            }
        }
        user.setRoleList(roleList);

        user.setLoginName("wx_user_" + IdGen.uuid().substring(0,15));
        user.setPassword(SystemService.entryptPassword(wxDefaultPassword));
        user.setOriginPassword(wxDefaultPassword);
        user.setName(userInfo.getNickName());
        user.setOpenId(userInfo.getOpenId());
        user.setPhoto(userInfo.getAvatarUrl());
        user.setIsFront("1");
        user.setAllowBindAccount("0");

        // 保存用户信息
        systemService.saveUser(user);
        // 清除当前用户缓存
        if (user.getLoginName().equals(UserUtils.getUser().getLoginName())){
            UserUtils.clearCache();
        }

        return user;
    }
}

utils

代码语言:javascript
复制
package com.dfht.common.web;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * jwt工具类
 * @author liuzhiping
 * @date 2018-4-27 22:00:49
 */
@Component
public class JwtUtils {
    private Logger logger = LoggerFactory.getLogger(getClass());

    //@Value("#{APP_PROP['jwt.secret']}")
    @Value("${jwt.secret}")
    private String secret;
    //@Value("#{APP_PROP['jwt.expire']}")
    @Value("${jwt.expire}")
    private long expire;
    //@Value("#{APP_PROP['jwt.header']}")
    @Value("${jwt.header}")
    private String header;

    /**
     * 生成jwt token
     */
    public String generateToken(String userId) {
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);

        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(userId+"")
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public Claims getClaimByToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        }catch (Exception e){
            logger.debug("validate is token error ", e);
            return null;
        }
    }

    /**
     * token是否过期
     * @return  true:过期
     */
    public boolean isTokenExpired(Date expiration) {
        return expiration.before(new Date());
    }

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public long getExpire() {
        return expire;
    }

    public void setExpire(long expire) {
        this.expire = expire;
    }

    public String getHeader() {
        return header;
    }

    public void setHeader(String header) {
        this.header = header;
    }
}

xml

配置 app 拦截器

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">
    
    <description>Spring MVC Configuration</description>
    
    <!-- 加载配置属性文件 -->
	<context:property-placeholder ignore-unresolvable="true" location="classpath:dfht.properties" />
	
	<!-- 使用Annotation自动注册Bean,只扫描@Controller -->
	<context:component-scan base-package="com.dfht" use-default-filters="false"><!-- base-package 如果多个,用“,”分隔 -->
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
    
	<!-- 默认的注解映射的支持,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -->
	<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
		<mvc:message-converters register-defaults="true">
			<!-- 将StringHttpMessageConverter的默认编码设为UTF-8 -->
			<bean class="org.springframework.http.converter.StringHttpMessageConverter">
		    	<constructor-arg value="UTF-8" />
			</bean>
			<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/> 
			<!-- 将Jackson2HttpMessageConverter的默认格式化输出为false -->
			<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="supportedMediaTypes">
                	<list><value>application/json;charset=UTF-8</value></list>
                </property>
                <property name="prettyPrint" value="false"/>
                <property name="objectMapper">  
                    <bean class="com.dfht.common.mapper.JsonMapper"></bean>
                </property> 
            </bean>
            <!-- 使用XML格式输出数据 -->
            <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
		        <constructor-arg>
		        	<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
				        <property name="streamDriver">
				            <bean class="com.thoughtworks.xstream.io.xml.StaxDriver"/>
				        </property>
				        <property name="annotatedClasses">
				            <list>
				                <value>com.dfht.common.persistence.BaseEntity</value>
				                <value>com.dfht.common.supcan.treelist.TreeList</value>
				                <value>com.dfht.common.supcan.treelist.cols.Col</value>
				                <value>com.dfht.common.supcan.treelist.cols.Group</value>
				            </list>
				        </property>
				    </bean>
		        </constructor-arg>
		        <property name="supportedMediaTypes" value="application/xml"></property>
			</bean>
		</mvc:message-converters>
		<!-- app接口模块启用时开启 -->
		<mvc:argument-resolvers>
			<bean class="com.dfht.modules.app.resolver.LoginUserHandlerMethodArgumentResolver"></bean>
		</mvc:argument-resolvers>
	</mvc:annotation-driven>
	
    <!-- REST中根据URL后缀自动判定Content-Type及相应的View -->
	<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
	    <property name="mediaTypes" >
	        <map> 
                <entry key="xml" value="application/xml"/> 
                <entry key="json" value="application/json"/> 
            </map>
	    </property>
        <property name="ignoreAcceptHeader" value="true"/>
        <property name="favorPathExtension" value="true"/>
	</bean>
	
	<bean id="beetlConfig" class="org.beetl.ext.spring.BeetlGroupUtilConfiguration" init-method="init">
        <property name="root" value="/" />
		<property name="functions">
			<map>
				<!-- 定义SpEL方法 -->
				<entry key="spel">
					<bean class="org.beetl.ext.spring.SpELFunction"/>
				</entry>
			</map>
		</property>
		<property name="functionPackages">
			<map>
				<entry key="sputil">
					<bean class="org.beetl.ext.spring.UtilsFunctionPackage"/>
				</entry>
			</map>
		</property>
	</bean>
	
	<!-- Beetl视图解析器 -->
	<bean id="viewResolver" class="org.beetl.ext.spring.BeetlSpringViewResolver">
	    <property name="order" value="0"/>
        <property name="suffix" value=".html"/>
        <property name="contentType" value="text/html;charset=UTF-8"/>
	</bean>
	
	<!-- 定义JSP视图解析器 -->
	<bean name="JSPViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    	<!-- 注意JSP的这个视图解析器order必须在最后 -->
	    <property name="order" value="0"/>
		<property name="prefix" value="${web.view.prefix}"/>
		<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/> <!-- 不能用jstl的那个 -->
		<property name="contentType" value="text/html;charset=UTF-8"/>
		<property name="suffix" value=".jsp"/>
	</bean>

	<!-- 对静态资源文件的访问, 将无法mapping到Controller的path交给default servlet handler处理 -->
	<mvc:default-servlet-handler />
	
	<!-- 静态资源映射 -->
    <mvc:resources mapping="/static/**" location="/static/" cache-period="31536000"/>
	
	<!-- 定义无Controller的path<->view直接映射 -->
	<mvc:view-controller path="/" view-name="redirect:${web.view.index}"/>
	
	<!-- 拦截器配置,拦截顺序:先执行后定义的,排在第一位的最后执行。-->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="${adminPath}/**" />
			<mvc:mapping path="${apiPath}/**"/>
			<mvc:exclude-mapping path="${adminPath}/"/>
			<mvc:exclude-mapping path="${adminPath}/login"/>
			<mvc:exclude-mapping path="${adminPath}/sys/menu/tree"/>
			<mvc:exclude-mapping path="${adminPath}/sys/menu/treeData"/>
			<mvc:exclude-mapping path="${adminPath}/oa/oaNotify/self/count"/>
			<bean class="com.dfht.modules.sys.interceptor.LogInterceptor" />
		</mvc:interceptor>
		<!-- app拦截器 -->
		<mvc:interceptor>
			<mvc:mapping path="${apiPath}/**" />
			<bean class="com.dfht.modules.app.interceptor.AuthorizationInterceptor" />
		</mvc:interceptor>
	</mvc:interceptors>

	<!-- 支持Shiro对Controller的方法级AOP安全控制 begin-->
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
		<property name="proxyTargetClass" value="true" />
	</bean>
	
	<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionMappings">
			<props>
				<prop key="org.apache.shiro.authz.UnauthorizedException">other/403</prop>
				<prop key="java.lang.Throwable">error/500</prop>
				<prop key="Exception">error/500</prop>
			</props>
			</property>
	</bean>
	<!-- 支持Shiro对Controller的方法级AOP安全控制 end -->
	
	<!-- 上传文件拦截,设置最大上传文件大小   10M=10*1024*1024(B)=10485760 bytes -->  
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
		<property name="maxUploadSize" value="${web.maxUploadSize}" />  
	</bean>

	<!-- swagger api配置 -->
	<bean id="swaggerConfig" class="com.dfht.modules.app.config.SwaggerConfig" />
	<!-- 以下两个mapping必须配置,否则在服务器上无法访问swgger-ui.html -->
	<mvc:resources mapping="/swagger-ui.html" location="classpath:/META-INF/resources/"/>
	<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>
	
	<!-- 允许跨域 -->
	<mvc:cors>
        <mvc:mapping path="/**" allowed-origins="*" allow-credentials="true" max-age="3600" allowed-methods="GET,POST,DELETE,OPTIONS"/>
    </mvc:cors>
</beans>

interceptor

代码语言:javascript
复制
package com.dfht.modules.app.interceptor;


import com.dfht.common.utils.StringUtils;
import com.dfht.common.web.JwtUtils;
import com.dfht.modules.app.annotation.Login;
import com.dfht.modules.app.exception.AppException;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 验证是否需要登录
 * @author liuzhiping
 * @date 2018-4-16 19:08:26
 */
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private JwtUtils jwtUtils;

    public static final String USER_KEY = "userId";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        Login annotation;

        if(handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(Login.class);
        }else{
            return true;
        }

        if(annotation == null){
            return true;
        }

        //获取用户凭证
        String token = request.getHeader(jwtUtils.getHeader());
        if(StringUtils.isBlank(token)){
            token = request.getParameter(jwtUtils.getHeader());
        }

        //凭证为空
        if(StringUtils.isBlank(token)){
            throw new AppException(jwtUtils.getHeader() + "不能为空", HttpStatus.UNAUTHORIZED.value());
        }

        Claims claims = jwtUtils.getClaimByToken(token);
        if(claims == null || jwtUtils.isTokenExpired(claims.getExpiration())){
            throw new AppException(jwtUtils.getHeader() + "失效,请重新登录", HttpStatus.UNAUTHORIZED.value());
        }

        //设置userId到request里,后续根据userId,获取用户信息
        request.setAttribute(USER_KEY, claims.getSubject());

        return true;

    }
}

annotation

代码语言:javascript
复制
package com.dfht.modules.app.annotation;

import java.lang.annotation.*;

/**
 * app登录效验
 * @author liuzhiping
 * @date 2018年4月16日18:53:26
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
}

exception

代码语言:javascript
复制
package com.dfht.modules.app.exception;

/**
 * 自定义异常
 * 
 * @author liuzhiping
 * @date 2018年4月17日10:05:46
 */
public class AppException extends RuntimeException {
	private static final long serialVersionUID = 1L;
	
    private String msg;
    private int code = 500;
    
    public AppException(String msg) {
		super(msg);
		this.msg = msg;
	}
	
	public AppException(String msg, Throwable e) {
		super(msg, e);
		this.msg = msg;
	}
	
	public AppException(String msg, int code) {
		super(msg);
		this.msg = msg;
		this.code = code;
	}
	
	public AppException(String msg, int code, Throwable e) {
		super(msg, e);
		this.msg = msg;
		this.code = code;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}
	
	
}
代码语言:javascript
复制
package com.dfht.modules.app.exception;

import com.dfht.common.web.R;
import org.apache.shiro.authz.AuthorizationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

/**
 * 异常处理器
 * 
 * @author liuzhiping
 * @date 2018年4月16日20:24:11
 */
@ControllerAdvice
public class AppExceptionHandler {
	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 处理自定义异常
	 */
	@ExceptionHandler(AppException.class)
	@ResponseBody
	public R handleRRException(AppException e){
		R r = new R();
		r.put("code", e.getCode());
		r.put("msg", e.getMessage());
		return r;
	}
	
	@ExceptionHandler(NoHandlerFoundException.class)
	@ResponseBody
	public R handlerNoFoundException(Exception e) {
		logger.error(e.getMessage(), e);
		return R.error(404, "路径不存在,请检查路径是否正确");
	}

	@ExceptionHandler(DuplicateKeyException.class)
	@ResponseBody
	public R handleDuplicateKeyException(DuplicateKeyException e){
		logger.error(e.getMessage(), e);
		return R.error("数据库中已存在该记录");
	}

	@ExceptionHandler(AuthorizationException.class)
	@ResponseBody
	public R handleAuthorizationException(AuthorizationException e){
		logger.error(e.getMessage(), e);
		return R.error("没有权限,请联系管理员授权");
	}

	@ExceptionHandler(Exception.class)
	@ResponseBody
 	public R handleException(Exception e){
		logger.error(e.getMessage(), e);
		return R.error();
	}
}

测试

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-10-19|,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目的
  • 设计思路
  • 小程序
    • wxml
      • js
      • Java 后端
        • pom
          • controller
            • service
              • utils
                • xml
                  • interceptor
                    • annotation
                      • exception
                        • 测试
                        相关产品与服务
                        访问管理
                        访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档