导入依赖:
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 + ‘’’ +
‘}’;
}
} - 服务号appid
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 + ‘’’ +
‘}’;
}
} - 成员UserID
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>
***拦截器在下一章***