자바 에서 Shiro,JWT 를 바탕 으로 위 챗 애플 릿 로그 인 전체 예 및 실현 과정 을 실현 합 니 다.
본 고 는 위 챗 애플 릿 사용자 정의 로그 인 을 위 한 완전한 예 입 니 다.기술 스 택 은 SpringBoot+Shiro+JWT+JPA+Redis 입 니 다.
이 예 에 관심 이 있 거나 언어 표현 이 지루 하 다 고 생각 되면 완전한 프로젝트 주 소 를 볼 수 있 습 니 다.https://github.com/EalenXie/shiro-jwt-applet
주요 구현:애플 릿 의 사용자 정의 로그 인 을 실현 하고 사용자 정의 로그 인 상태 token 을 애플 릿 에 로그 인 증빙 으로 되 돌려 줍 니 다.사용자 의 정 보 는 데이터베이스 에 저장 되 어 있 으 며,로그 인 상태 token 캐 시 는 redis 에 있 습 니 다.
효 과 는 다음 과 같 습 니 다:
1.우선 우리 애플 릿 에서 wx.login()을 호출 하여 임시 증빙 코드 를 가 져 옵 니 다.
2.이 코드 를 사용 하여 애플 릿 로그 인 을 통 해 사용자 정의 로그 인 상태 token 을 가 져 오고 postman 으로 테스트 합 니 다.
3.인증 이 필요 한 인 터 페 이 스 를 호출 하고 이 token 을 가지 고 감 권 을 하여 되 돌아 오 는 정 보 를 얻 습 니 다. :
전방 고에너지,본 사례 의 코드 설명 이 비교적 많 고 다음은 주요 한 구축 절차 이다.
1.먼저 Maven 프로젝트 shiro-jwt-applet,pom 의존,주로 shiro 와 jwt 의 의존,그리고 SpringBoot 의 기초 의존.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>name.ealen</groupId>
<artifactId>shiro-jwt-applet</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>shiro-wx-jwt</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.애플 리 케 이 션.yml 을 설정 합 니 다.주로 애플 리 케 이 션 appid 와 secret,그리고 데이터베이스 와 redis 를 설정 합 니 다.
##
spring:
application:
name: shiro-jwt-applet
jpa:
hibernate:
ddl-auto: create #
# datasource
datasource:
url: jdbc:mysql://localhost:3306/yourdatabase
username: yourname
password: yourpass
driver-class-name: com.mysql.jdbc.Driver
# redis
redis:
database: 0
host: localhost
port: 6379
# appid /appsecret
wx:
applet:
appid: yourappid
appsecret: yourappsecret
3.우리 가 저장 한 위 챗 애플 릿 로그 인 을 정의 하 는 실체 정보 WxAccount :
package name.ealen.domain.entity;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* Created by EalenXie on 2018/11/26 10:26.
* ,
*/
@Entity
@Table
public class WxAccount {
@Id
@GeneratedValue
private Integer id;
private String wxOpenid;
private String sessionKey;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastTime;
/**
* getter/setter
*/
}
데이터베이스 WxAccountRepository 에 간단 한 dao 접근:
package name.ealen.domain.repository;
import name.ealen.domain.entity.WxAccount;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* Created by EalenXie on 2018/11/26 10:32.
*/
public interface WxAccountRepository extends JpaRepository<WxAccount, Integer> {
/**
* OpenId
*/
WxAccount findByWxOpenid(String wxOpenId);
}
4.저희 가 사용 하 는 서비스 설명 Wx AppletService 를 정의 합 니 다.
package name.ealen.application;
import name.ealen.interfaces.dto.Token;
/**
* Created by EalenXie on 2018/11/26 10:40.
*
*/
public interface WxAppletService {
/**
* , ,
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
* 1 . code。
* 2 . code2session openid session_key
* 3 . openid session_key (Token)
* 4 . (Token) 。
* 5 . api, header Authorization token
*
* @param code wx.login code, code2session
* @return Token token JWT
*/
public Token wxUserLogin(String code);
}
위 챗 애플 릿 token 대상 에 게 Token 설명 을 되 돌려 줍 니 다:
package name.ealen.interfaces.dto;
/**
* Created by EalenXie on 2018/11/26 18:49.
* DTO token
*/
public class Token {
private String token;
public Token(String token) {
this.token = token;
}
/**
* getter/setter
*/
}
5.필요 한 기본 구성 요소,RestTemplate,Redis 설정:
package name.ealen.infrastructure.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* Created by EalenXie on 2018-03-23 07:37
* RestTemplate
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(1000 * 60); // 60
factory.setConnectTimeout(1000 * 10); // 10
return factory;
}
}
Redis 설정.이 예 는 Springboot 2.0 의 쓰기 입 니 다.
package name.ealen.infrastructure.config;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
/**
* Created by EalenXie on 2018-03-23 07:37
* Redis
*/
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
return RedisCacheManager.create(factory);
}
}
6.JWT 의 핵심 필터 설정.Shiro 의 Basic Http AuthenticationFilter 를 계승 하여 인증 권 의 여과 방법 을 다시 썼 습 니 다.
package name.ealen.infrastructure.config.jwt;
import name.ealen.domain.vo.JwtToken;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by EalenXie on 2018/11/26 10:26.
* JWT
* Filter, BasicHttpAuthenticationFilter, 。
* preHandle->isAccessAllowed->isLoginAttempt->executeLogin
*/
public class JwtFilter extends BasicHttpAuthenticationFilter {
/**
*
* header Authorization
*/
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
String auth = getAuthzHeader(request);
return auth != null && !auth.equals("");
}
/**
* ,
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (isLoginAttempt(request, response)) {
JwtToken token = new JwtToken(getAuthzHeader(request));
getSubject(request, response).login(token);
}
return true;
}
/**
*
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
// option , option
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
}
JWT 의 핵심 설정(Token 의 암호 화 생 성,JWT 연장,복호화 검증 포함):
package name.ealen.infrastructure.config.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import name.ealen.domain.entity.WxAccount;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* Created by EalenXie on 2018/11/22 17:16.
*/
@Component
public class JwtConfig {
/**
* JWT
*/
private static final String SECRET_KEY = "5371f568a45e5ab1f442c38e0932aef24447139b";
/**
* JWT 7200 ,
*/
private static long expire_time = 7200;
@Autowired
private StringRedisTemplate redisTemplate;
/**
* token
* : token redis ,
* redis jwt token
*
* @param wxAccount
* @return jwt token
*/
public String createTokenByWxAccount(WxAccount wxAccount) {
String jwtId = UUID.randomUUID().toString(); //JWT ID, key
//1 . token
Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
String token = JWT.create()
.withClaim("wxOpenId", wxAccount.getWxOpenid())
.withClaim("sessionKey", wxAccount.getSessionKey())
.withClaim("jwt-id", jwtId)
.withExpiresAt(new Date(System.currentTimeMillis() + expire_time*1000)) //JWT
.sign(algorithm);
//2 . Redis JWT, : JWT
redisTemplate.opsForValue().set("JWT-SESSION-" + jwtId, token, expire_time, TimeUnit.SECONDS);
return token;
}
/**
* token
* 1 . token , jwt-id , redis redisToken,
* 2 . redisToken , token
*
* @param token
* @return
*/
public boolean verifyToken(String token) {
try {
//1 . token , jwt-id , redis redisToken,
String redisToken = redisTemplate.opsForValue().get("JWT-SESSION-" + getJwtIdByToken(token));
if (!redisToken.equals(token)) return false;
//2 . JWTVerifier
Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("wxOpenId", getWxOpenIdByToken(redisToken))
.withClaim("sessionKey", getSessionKeyByToken(redisToken))
.withClaim("jwt-id", getJwtIdByToken(redisToken))
.acceptExpiresAt(System.currentTimeMillis() + expire_time*1000 ) //JWT
.build();
//3 . token
verifier.verify(redisToken);
//4 . Redis JWT
redisTemplate.opsForValue().set("JWT-SESSION-" + getJwtIdByToken(token), redisToken, expire_time, TimeUnit.SECONDS);
return true;
} catch (Exception e) { //
return false;
}
}
/**
* Token wxOpenId( : token , wxOpenId, )
*/
public String getWxOpenIdByToken(String token) throws JWTDecodeException {
return JWT.decode(token).getClaim("wxOpenId").asString();
}
/**
* Token sessionKey
*/
public String getSessionKeyByToken(String token) throws JWTDecodeException {
return JWT.decode(token).getClaim("sessionKey").asString();
}
/**
* Token jwt-id
*/
private String getJwtIdByToken(String token) throws JWTDecodeException {
return JWT.decode(token).getClaim("jwt-id").asString();
}
}
7.Shiro 의 Realm 설정 을 사용자 정의 합 니 다.Realm 은 사용자 정의 로그 인 및 권한 수 여 를 위 한 논리 적 설정 입 니 다.
package name.ealen.infrastructure.config.shiro;
import name.ealen.domain.vo.JwtToken;
import name.ealen.infrastructure.config.jwt.JwtConfig;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* Created by EalenXie on 2018/11/26 12:12.
* Realm allRealm() realm
*/
@Component
public class ShiroRealmConfig {
@Resource
private JwtConfig jwtConfig;
/**
* realm, , realm
*/
public List<Realm> allRealm() {
List<Realm> realmList = new LinkedList<>();
AuthorizingRealm jwtRealm = jwtRealm();
realmList.add(jwtRealm);
return Collections.unmodifiableList(realmList);
}
/**
* JWT Realm
* Realm supports() JWT
*/
private AuthorizingRealm jwtRealm() {
AuthorizingRealm jwtRealm = new AuthorizingRealm() {
/**
* : , Shiro
* JWTToken Shiro token, ,
*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return new SimpleAuthorizationInfo();
}
/**
* token
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
String jwtToken = (String) token.getCredentials();
String wxOpenId = jwtConfig.getWxOpenIdByToken(jwtToken);
String sessionKey = jwtConfig.getSessionKeyByToken(jwtToken);
if (wxOpenId == null || wxOpenId.equals(""))
throw new AuthenticationException("user account not exits , please check your token");
if (sessionKey == null || sessionKey.equals(""))
throw new AuthenticationException("sessionKey is invalid , please check your token");
if (!jwtConfig.verifyToken(jwtToken))
throw new AuthenticationException("token is invalid , please check your token");
return new SimpleAuthenticationInfo(token, token, getName());
}
};
jwtRealm.setCredentialsMatcher(credentialsMatcher());
return jwtRealm;
}
/**
* : , JWT , , true( , false, )
*/
private CredentialsMatcher credentialsMatcher() {
return (token, info) -> true;
}
}
Shiro 의 핵심 설정,Realm 설정 포함:
package name.ealen.infrastructure.config.shiro;
import name.ealen.infrastructure.config.jwt.JwtFilter;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;
/**
* Created by EalenXie on 2018/11/22 18:28.
*/
@Configuration
public class ShirConfig {
/**
* SecurityManager, , ;
* Subject, Subject SecurityManager, Subject SecurityManager
* DefaultWebSecurityManager :
* DefaultSubjectDAO( DefaultSessionStorageEvaluator)
* DefaultWebSubjectFactory
* ModularRealmAuthenticator
*/
@Bean
public DefaultWebSecurityManager securityManager(ShiroRealmConfig shiroRealmConfig) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealms(shiroRealmConfig.allRealm()); // realm
DefaultSubjectDAO subjectDAO = (DefaultSubjectDAO) securityManager.getSubjectDAO();
// session
DefaultSessionStorageEvaluator evaluator = (DefaultSessionStorageEvaluator) subjectDAO.getSessionStorageEvaluator();
evaluator.setSessionStorageEnabled(Boolean.FALSE);
subjectDAO.setSessionStorageEvaluator(evaluator);
return securityManager;
}
/**
* Shiro
*/
@Bean
public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
Map<String, Filter> filterMap = new HashMap<>();
filterMap.put("jwt", new JwtFilter());
factoryBean.setFilters(filterMap);
factoryBean.setSecurityManager(securityManager);
Map<String, String> filterRuleMap = new HashMap<>();
// api
filterRuleMap.put("/api/wx/user/login/**", "anon");
filterRuleMap.put("/api/response/**", "anon");
// JWT Filter
filterRuleMap.put("/**", "jwt");
factoryBean.setFilterChainDefinitionMap(filterRuleMap);
return factoryBean;
}
/**
*
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); // cglib,
return defaultAdvisorAutoProxyCreator;
}
/**
*
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
*
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
Shiro 인증 에 사용 할 JwtToken 대상:
package name.ealen.domain.vo;
import org.apache.shiro.authc.AuthenticationToken;
/**
* Created by EalenXie on 2018/11/22 18:21.
* token vo , AuthenticationToken
*/
public class JwtToken implements AuthenticationToken {
private String token;
public JwtToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
8.실체의 행위 와 업무 논 리 를 실현 합 니 다.이 예 는 주로 위 챗 인터페이스 code2session 을 호출 하고 token 으로 되 돌아 가 는 것 입 니 다.
package name.ealen.domain.service;
import name.ealen.application.WxAppletService;
import name.ealen.domain.entity.WxAccount;
import name.ealen.domain.repository.WxAccountRepository;
import name.ealen.domain.vo.Code2SessionResponse;
import name.ealen.infrastructure.config.jwt.JwtConfig;
import name.ealen.infrastructure.util.HttpUtil;
import name.ealen.infrastructure.util.JSONUtil;
import name.ealen.interfaces.dto.Token;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URI;
import java.util.Date;
/**
* Created by EalenXie on 2018/11/26 10:50.
*
*/
@Service
public class WxAccountService implements WxAppletService {
@Resource
private RestTemplate restTemplate;
@Value("${wx.applet.appid}")
private String appid;
@Value("${wx.applet.appsecret}")
private String appSecret;
@Resource
private WxAccountRepository wxAccountRepository;
@Resource
private JwtConfig jwtConfig;
/**
* code2session
* : https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
*/
private String code2Session(String jsCode) {
String code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session";
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("appid", appid);
params.add("secret", appSecret);
params.add("js_code", jsCode);
params.add("grant_type", "authorization_code");
URI code2Session = HttpUtil.getURIwithParams(code2SessionUrl, params);
return restTemplate.exchange(code2Session, HttpMethod.GET, new HttpEntity<String>(new HttpHeaders()), String.class).getBody();
}
/**
* , ,
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
*
* @param code wx.login code, code2session
* @return token JWT
*/
@Override
public Token wxUserLogin(String code) {
//1 . code2session JSON
String resultJson = code2Session(code);
//2 .
Code2SessionResponse response = JSONUtil.jsonString2Object(resultJson, Code2SessionResponse.class);
if (!response.getErrcode().equals("0"))
throw new AuthenticationException("code2session : " + response.getErrmsg());
else {
//3 .
WxAccount wxAccount = wxAccountRepository.findByWxOpenid(response.getOpenid());
if (wxAccount == null) {
wxAccount = new WxAccount();
wxAccount.setWxOpenid(response.getOpenid()); //
}
//4 . sessionKey
wxAccount.setSessionKey(response.getSession_key());
wxAccount.setLastTime(new Date());
wxAccountRepository.save(wxAccount);
//5 . JWT Token
String token = jwtConfig.createTokenByWxAccount(wxAccount);
return new Token(token);
}
}
}
애플 릿 code2session 인터페이스의 반환 VO 대상 Code2Session Response:
package name.ealen.domain.vo;
/**
* Code2Session
* API : https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
*/
public class Code2SessionResponse {
private String openid;
private String session_key;
private String unionid;
private String errcode = "0";
private String errmsg;
private int expires_in;
/**
* getter/setter
*/
}
9. Google 의 인터페이스 정 보 를 정의 합 니 다.이 예 는 로그 인 으로 token 을 가 져 오 는 api 와 인증 이 필요 한 테스트 api 를 포함 합 니 다.
package name.ealen.interfaces.facade;
import name.ealen.application.WxAppletService;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* Created by EalenXie on 2018/11/26 10:44.
* API
*/
@RestController
public class WxAppletController {
@Resource
private WxAppletService wxAppletService;
/**
* api
* token
*/
@PostMapping("/api/wx/user/login")
public ResponseEntity wxAppletLoginApi(@RequestBody Map<String, String> request) {
if (!request.containsKey("code") || request.get("code") == null || request.get("code").equals("")) {
Map<String, String> result = new HashMap<>();
result.put("msg", " code code ");
return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
} else {
return new ResponseEntity<>(wxAppletService.wxUserLogin(request.get("code")), HttpStatus.OK);
}
}
/**
* @RequiresAuthentication , header authorization
*/
@RequiresAuthentication
@PostMapping("/sayHello")
public ResponseEntity sayHello() {
Map<String, String> result = new HashMap<>();
result.put("words", "hello World");
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
10.주 클래스 를 실행 하고 데이터베이스 와 redis 의 연결 을 검사 하 며 테스트 를 진행 합 니 다.
package name.ealen;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Created by EalenXie on 2018/11/26 10:25.
*/
@SpringBootApplication
public class ShiroJwtAppletApplication {
public static void main(String[] args) {
SpringApplication.run(ShiroJwtAppletApplication.class, args);
}
총결산위 에서 말 한 것 은 편집장 이 여러분 에 게 소개 한 자바 에서 Shiro,JWT 를 바탕 으로 위 챗 애플 릿 로그 인 을 실현 하 는 완전한 예 와 실현 과정 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 저 에 게 메 시 지 를 남 겨 주세요.편집장 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!