微信授权登录(H5为例)

导入依赖

com.auth0
java-jwt
3.4.0

登录类:
package com.beagledata.gaea.securitydoc.controller;

import com.alibaba.fastjson.JSONObject;
import com.beagledata.gaea.securitydoc.config.LoginConfigs;
import com.beagledata.gaea.securitydoc.entity.User;
import com.beagledata.gaea.securitydoc.service.UserService;
import com.beagledata.utils.RestClient;
import com.beagledata.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**

  • Created by mahongfei on 2019/9/3.
    */
    @Controller
    @RequestMapping(“login”)
    public class LoginController {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private LoginConfigs loginConfigs;
    @Autowired
    private UserService userService;

    /**

    • @Author: mahongfei

    • @description: 微信H5授权登录
      */
      @GetMapping(“wxlogin_userinfo”)
      public String wxLoginUserInfo(String returnUrl, String scope) {
      if (StringUtil.isBlank(returnUrl)) {
      returnUrl = loginConfigs.getWebApplicationUrl();
      }

      if (StringUtil.isBlank(scope)) {
      scope = “snsapi_userinfo”;
      }

      return getOauthUrl(returnUrl, scope);
      }

    /**

    • @Author: mahongfei

    • @description: 获取code并返回到回调接口
      */
      private String getOauthUrl(String returnUrl, String scope) {
      String oauth2Url = String.format(
      “%s/login/oauth_response?fromUrl=%s&scope=%s”,
      loginConfigs.getApiApplicationUrl(),
      encodeUrl(returnUrl),
      scope
      );

      return String.format(
      “redirect:%s/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&agentid=%s&state=123&#wechat_redirect”,
      loginConfigs.getAppCodeAddress(),
      loginConfigs.getAppid(),
      encodeUrl(oauth2Url),
      scope,
      loginConfigs.getAgentid()
      );
      }

    private String encodeUrl(String url) {
    try {
    return URLEncoder.encode(url, “UTF-8”);
    } catch (UnsupportedEncodingException e) {
    }
    return null;
    }

    /**

    • @Author: mahongfei

    • @description: 通过code返回用户信息
      */
      @GetMapping(“oauth_response”)
      public String oauthResponse(String code, String fromUrl, String scope) {
      if (code == null) {
      return toLoginFail();
      }
      //获取token
      JSONObject tokenJson = getAccessToken();
      if (!tokenJson.containsKey(“access_token”)) {
      return toLoginFail();
      }
      //获取userid
      User user = new User();
      JSONObject userInfojson = getInfo(tokenJson.getString(“access_token”), code);
      if (!userInfojson.containsKey(“UserId”) && !userInfojson.containsKey(“OpenId”)) {
      return toLoginFail();
      }
      //获取详情
      JSONObject userDetailJson;
      if (null != userInfojson && null != userInfojson.getString(“UserId”)) {
      userDetailJson = getUserDetail(tokenJson.getString(“access_token”), userInfojson.getString(“UserId”));
      } else if (null != userInfojson && null != userInfojson.getString(“OpenId”)) {
      userDetailJson = getUserDetail(tokenJson.getString(“access_token”), userInfojson.getString(“OpenId”));
      } else {
      logger.info(“获取用户id错误”);
      throw new IllegalArgumentException(“获取id错误”);
      }

      if (!userDetailJson.containsKey(“userid”)) {
      return toLoginFail();
      }
      //将用户详情添加到user中登录
      if (“snsapi_privateinfo”.equals(scope)) {
      user.setUserid(userDetailJson.getString(“userid”));
      user.setName(userDetailJson.getString(“name”));
      user.setDepartment(userDetailJson.getString(“department”));
      user.setPosition(userDetailJson.getString(“position”));
      user.setMobile(userDetailJson.getString(“mobile”));
      user.setGender(userDetailJson.getIntValue(“gender”));
      user.setEmail(userDetailJson.getString(“email”));
      user.setAvatar(userDetailJson.getString(“avatar”));
      } else if (“snsapi_userinfo”.equals(scope) ) {
      user.setUserid(userDetailJson.getString(“userid”));
      user.setName(userDetailJson.getString(“name”));
      user.setDepartment(userDetailJson.getString(“department”));
      user.setPosition(userDetailJson.getString(“position”));
      user.setGender(userDetailJson.getIntValue(“gender”));
      user.setAvatar(userDetailJson.getString(“avatar”));
      if (null != userDetailJson.getString(“mobile”)) {
      user.setMobile(userDetailJson.getString(“mobile”));
      }
      if (null != userDetailJson.getString(“email”)) {
      user.setEmail(userDetailJson.getString(“email”));
      }
      } else {
      user.setUserid(userDetailJson.getString(“userid”));
      }

      return “redirect:” + returnWithToken(fromUrl, userService.login(user));
      }

    /**

    • @Author: mahongfei
    • @description: 获取token
      */
      private JSONObject getAccessToken() {
      String result = RestClient.getForObject(
      String.format(
      “%s/cgi-bin/gettoken?corpid=%s&corpsecret=%s”,
      loginConfigs.getAppAddress(),
      loginConfigs.getAppid(),
      loginConfigs.getAppSecret()
      ),
      String.class
      );
      return JSONObject.parseObject(result);
      }

    /**

    • @Author: mahongfei
    • @description: 获取成员的详细信息
      */
      private JSONObject getUserDetail(String accessToken, String UserId) {
      String result = RestClient.getForObject(
      String.format(
      “%s/cgi-bin/user/get?access_token=%s&userid=%s”,
      loginConfigs.getAppAddress(),
      accessToken,
      UserId),
      String.class
      );
      System.out.println(result);
      return JSONObject.parseObject(result);
      }

    /**

    • @Author: mahongfei
    • @description: 获取成员的userid、user_ticket
      */
      private JSONObject getInfo(String accessToken, String code) {
      String result = RestClient.getForObject(
      String.format(
      “%s/cgi-bin/user/getuserinfo?access_token=%s&code=%s”,
      loginConfigs.getAppAddress(),
      accessToken,
      code
      ),
      String.class
      );
      return JSONObject.parseObject(result);
      }

    /**

    • @Author: mahongfei
    • @description: 返回token
      */
      private String returnWithToken(String returnUrl, User user) {
      if (user == null && user.getId() == null) {
      return toLoginFail();
      }
      StringBuilder url = new StringBuilder(returnUrl);
      if (returnUrl.contains("?")) {
      url.append("&token=");
      } else {
      url.append("?token=");
      }
      url.append(userService.createJWTToken(user));
      return url.toString();
      }

    /**

    • @Author: mahongfei
    • @description: 返回登录失败页面
      */
      private String toLoginFail() {
      return “redirect:” + loginConfigs.getWebApplicationUrl() + “loginfail”;
      }
      }

配置类:
package com.beagledata.gaea.securitydoc.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**

  • Created by mahongfei on 2019/9/3.
    /
    @Configuration
    @ConfigurationProperties(prefix = “config”)
    public class LoginConfigs {
    /
    *

    • 服务号appid
      /
      private String appid;
      /
      *
    • 服务号appsecret
      /
      private String appSecret;
      /
      *
    • html服务地址
      /
      private String webApplicationUrl;
      /
      *
    • api服务地址
      /
      private String apiApplicationUrl;
      /
      *
    • 企业应用id
      /
      private String agentid;
      /
      *
    • jwt token过期时间,单位:小时
      /
      private int tokenExpiresAt;
      /
      *
    • 企业应用地址
      /
      private String appAddress;
      /
      *
    • 企业应用code地址
      */
      private String appCodeAddress;

    public String getAppid() {
    return appid;
    }

    public void setAppid(String appid) {
    this.appid = appid;
    }

    public String getAppSecret() {
    return appSecret;
    }

    public void setAppSecret(String appSecret) {
    this.appSecret = appSecret;
    }

    public String getWebApplicationUrl() {
    return webApplicationUrl;
    }

    public void setWebApplicationUrl(String webApplicationUrl) {
    this.webApplicationUrl = webApplicationUrl;
    }

    public String getApiApplicationUrl() {
    return apiApplicationUrl;
    }

    public void setApiApplicationUrl(String apiApplicationUrl) {
    this.apiApplicationUrl = apiApplicationUrl;
    }

    public String getAgentid() {
    return agentid;
    }

    public void setAgentid(String agentid) {
    this.agentid = agentid;
    }

    public int getTokenExpiresAt() {
    return tokenExpiresAt;
    }

    public void setTokenExpiresAt(int tokenExpiresAt) {
    this.tokenExpiresAt = tokenExpiresAt;
    }

    public String getAppAddress() {
    return appAddress;
    }

    public void setAppAddress(String appAddress) {
    this.appAddress = appAddress;
    }

    public String getAppCodeAddress() {
    return appCodeAddress;
    }

    public void setAppCodeAddress(String appCodeAddress) {
    this.appCodeAddress = appCodeAddress;
    }

    @Override
    public String toString() {
    return “LoginConfigs{” +
    “appid=’” + appid + ‘’’ +
    “, appSecret=’” + appSecret + ‘’’ +
    “, webApplicationUrl=’” + webApplicationUrl + ‘’’ +
    “, apiApplicationUrl=’” + apiApplicationUrl + ‘’’ +
    “, agentid=’” + agentid + ‘’’ +
    “, tokenExpiresAt=” + tokenExpiresAt +
    “, appAddress=’” + appAddress + ‘’’ +
    “, appCodeAddress=’” + appCodeAddress + ‘’’ +
    ‘}’;
    }
    }

application.xml
config:
appid: ${SECURITYDOC_CONFIG_APPID:ww08216e9d335960ed} #企业的CorpID
app-secret: ${SECURITYDOC_CONFIG_APP_SECRET:JRT7Ps3IwliHZV4pGhnMwjN0YuIXJ2EjEdbqkuDOROA} #权限管理组的凭证密钥CorpIDSecret
agentid: ${SECURITYDOC_CONFIG_AGENTID:1000003} #企业应用的id
app-code-address: ${SECURITYDOC_APP_CODE_ADDRESS:https://open.weixin.qq.com} #获取code的地址
app-address: ${SECURITYDOC_APP_ADDRESS:https://qyapi.weixin.qq.com} #企业应用的地址
web-application-url: ${SECURITYDOC_CONFIG_WEB_APPLICATION_URL:http://localhost:33305/securitydoc/#/} # html服务地址
api-application-url: ${SECURITYDOC_CONFIG_API_APPLICATION_URL:intranet.buudoo.com:33305/securitydoc} # api服务地址
app-home: ${SECURITYDOC_CONFIG_APP_HOME:E:\fagui}
token-expires-at: ${SECURITYDOC_CONFIG_TOKEN_EXPIRES_AT:24} # jwt token过期时间,单位:小时
工具类:

package com.beagledata.gaea.securitydoc.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.Map;

/**

  • Created by liulu on 2018/8/10.
    */
    public class JWTUtils {
    private static final String SECRET = “7fdHS4”;
    private static Algorithm algorithm = Algorithm.HMAC256(SECRET);
    private static JWTVerifier verifier = JWT.require(algorithm).build();

    public static String create(Date expiresAt, Map<String, Object> payload) {
    JWTCreator.Builder builder = JWT.create().withExpiresAt(expiresAt);
    if (payload != null && !payload.isEmpty()) {
    for (Map.Entry<String, Object> me : payload.entrySet()) {
    String key = me.getKey();
    Object value = me.getValue();
    if (value instanceof String) {
    builder.withClaim(key, (String) value);
    } else if (value instanceof Date) {
    builder.withClaim(key, (Date) value);
    } else if (value instanceof Long) {
    builder.withClaim(key, (Long) value);
    } else if (value instanceof Double) {
    builder.withClaim(key, (Double) value);
    } else if (value instanceof Boolean) {
    builder.withClaim(key, (Boolean) value);
    } else if (value instanceof Integer) {
    builder.withClaim(key, (Integer) value);
    }
    }
    }
    return builder.sign(algorithm);
    }

    public static DecodedJWT decode(String token) {
    return verifier.verify(token);
    }
    }

package com.beagledata.gaea.securitydoc.common;

import com.beagledata.commons.ThreadHolder;
import com.beagledata.gaea.securitydoc.entity.User;

/**

  • Created by liulu on 2018/8/13.
    /
    public class SessionHolder {
    /
    *

    • @author liulu
    • 2018/8/13 下午 02:28
      */
      public static void set(User user) {
      ThreadHolder.set(user);
      }

    /**

    • @author liulu
    • 2018/8/13 下午 02:28
      */
      public static void remove() {
      ThreadHolder.remove();
      }

    /**

    • @author liulu

    • 2018/8/13 下午 02:40
      */
      public static int currentUserId() {
      User user = currentUser();
      if (user == null) {
      return 0;
      }

      Integer id = currentUser().getId();
      return id != null ? id : 0;
      }

    /**

    • @author liulu
    • 2018/8/13 下午 02:29
      */
      public static User currentUser() {
      return (User) ThreadHolder.get();
      }
      }

登录接口

package com.beagledata.gaea.securitydoc.entity;

/**

  • Created by mahongfei on 2019/9/3.
    /
    public class User extends BaseEntity {
    private static final long serialVersionUID = 695194018646397677L;
    /
    *

    • 成员UserID
      /
      private String userid;
      /
      *
    • 成员姓名
      /
      private String name;
      /
      *
    • 成员所属部门
      /
      private String department;
      /
      *
    • 职位信息
      /
      private String position;
      /
      *
    • 成员手机号,仅在用户同意snsapi_privateinfo授权时返回
      /
      private String mobile;
      /
      *
    • 性别。0表示未定义,1表示男性,2表示女性
      /
      private Integer gender;
      /
      *
    • 成员邮箱,仅在用户同意snsapi_privateinfo授权时返回
      /
      private String email;
      /
      *
    • 头像url。注:如果要获取小图将url最后的”/0”改成”/100”即可
      */
      private String avatar;

    public User() {
    }

    public String getUserid() {
    return userid;
    }

    public void setUserid(String userid) {
    this.userid = userid;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getDepartment() {
    return department;
    }

    public void setDepartment(String department) {
    this.department = department;
    }

    public String getPosition() {
    return position;
    }

    public void setPosition(String position) {
    this.position = position;
    }

    public String getMobile() {
    return mobile;
    }

    public void setMobile(String mobile) {
    this.mobile = mobile;
    }

    public Integer getGender() {
    return gender;
    }

    public void setGender(Integer gender) {
    this.gender = gender;
    }

    public String getEmail() {
    return email;
    }

    public void setEmail(String email) {
    this.email = email;
    }

    public String getAvatar() {
    return avatar;
    }

    public void setAvatar(String avatar) {
    this.avatar = avatar;
    }

    @Override
    public String toString() {
    return “User{” +
    “userid=’” + userid + ‘’’ +
    “, name=’” + name + ‘’’ +
    “, department=’” + department + ‘’’ +
    “, position=’” + position + ‘’’ +
    “, mobile=’” + mobile + ‘’’ +
    “, gender=” + gender +
    “, email=’” + email + ‘’’ +
    “, avatar=’” + avatar + ‘’’ +
    ‘}’;
    }
    }

package com.beagledata.gaea.securitydoc.controller;

import com.beagledata.gaea.securitydoc.common.Result;
import com.beagledata.gaea.securitydoc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**

  • Created by mahongfei on 2019/9/10.
    */
    @RestController
    @RequestMapping(“user”)
    public class UserController {
    @Autowired
    private UserService userService;

    /**

    • @Author: mahongfei
    • @description: 返回用户信息
      */
      @GetMapping(“info”)
      public Result getUserInfo() {
      return Result.newSuccess().withData(userService.getUserInfo());
      }
      }

package com.beagledata.gaea.securitydoc.service.impl;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.beagledata.gaea.securitydoc.common.SessionHolder;
import com.beagledata.gaea.securitydoc.config.LoginConfigs;
import com.beagledata.gaea.securitydoc.entity.User;
import com.beagledata.gaea.securitydoc.exception.UnauthorizedException;
import com.beagledata.gaea.securitydoc.mapper.UserMapper;
import com.beagledata.gaea.securitydoc.service.UserService;
import com.beagledata.gaea.securitydoc.utils.JWTUtils;
import com.beagledata.utils.IdUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Collections;
import java.util.Date;

/**

  • Created by mahongfei on 2019/9/3.
    */
    @Service
    public class UserServiceImpl implements UserService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LoginConfigs loginConfigs;
    @Autowired
    private RedisTemplate sessionRedisTemplate;

    @Override
    public User login(User user) {
    User user1 = userMapper.selectByUserId(user.getUserid());
    if (user1!= null) {
    userMapper.update(user);
    user.setId(user1.getId());
    user.setUuid(user1.getUuid());
    sessionRedisTemplate.delete(user.getUserid());
    sessionRedisTemplate.opsForHash().put(user.getUserid(), “loginUser”, user);
    } else {
    user.setUuid(IdUtil.UUID());
    userMapper.insert(user);
    sessionRedisTemplate.delete(user.getUserid());
    sessionRedisTemplate.opsForHash().put(user.getUserid(), “loginUser”, user);
    }
    return userMapper.selectByUserId(user.getUserid());
    }

    @Override
    public String createJWTToken(User user) {
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.HOUR, loginConfigs.getTokenExpiresAt());
    Date expiresAt = calendar.getTime();
    return JWTUtils.create(expiresAt, Collections.singletonMap(“userid”, user.getUserid()));
    }

    @Override
    public User decodeJWTToken(String token) {
    User user = null;
    try {
    DecodedJWT jwt = JWTUtils.decode(token);
    user = new User();
    if (!jwt.getClaim(“userid”).isNull()) {
    user.setUserid(jwt.getClaim(“userid”).asString());
    }
    } catch (Exception e) {
    throw new UnauthorizedException();
    }
    return user;
    }

    @Override
    public User getUserInfo() {
    try {
    User user = userMapper.selectByUserId(SessionHolder.currentUser().getUserid());
    if (user == null) {
    throw new IllegalArgumentException(“需要先授权”);
    }
    login(user);
    return user;
    } catch (Exception e) {
    logger.info(“获取用户信息失败:” + SessionHolder.currentUser());
    throw new IllegalStateException(“登录失败”);
    }
    }
    }

sql

<?xml version="1.0" encoding="UTF-8" ?>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO t_user
      (
        uuid, create_time, userid, name,
        department, position, mobile, gender, email, avatar
      )
    VALUES
      (
        #{uuid}, NOW(), #{userid}, #{name},
        #{department}, #{position}, #{mobile}, #{gender}, #{email}, #{avatar}
      )
</insert>

<update id="update">
    UPDATE t_user
    <set>
        update_time = NOW()
        <if test="name != null and name != ''">
            ,name = #{name}
        </if>
        <if test="position != null and position != ''">
            ,position = #{position}
        </if>
        <if test="department != null and department != ''">
            ,department = #{department}
        </if>
        <if test="mobile != null and mobile != ''">
            ,mobile = #{mobile}
        </if>
        <if test="gender != null">
            ,gender = #{gender}
        </if>
        <if test="email != null and email != ''">
            ,email = #{email}
        </if>
        <if test="avatar != null and avatar != ''">
            ,avatar = #{avatar}
        </if>
    </set>
    WHERE userid = #{userid}
</update>

<select id="selectByUserId" resultMap="userResultMap">
    SELECT id, uuid, create_time, userid, name,department, position, mobile, gender, email, avatar
    FROM t_user
    WHERE userid = #{userid}
</select>
***拦截器在下一章***
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值