1.项目创建
1、新建工程
2、选择打包方式,这边可以选择为打包为Jar包,或者传统的打包为War包
3、选择开发过程中使用到的技术,这边我选择的是Rest Repositories
4、新建测试用Controller
文件内容如下
- package com.xiaofangtech.example;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- @RestController
- public class HelloController {
- @RequestMapping("/greeting")
- public String hello()
- {
- return "Hello world";
- }
- }
5、以Srping Boot App 方式运行
正常运行后控制台如下
6、测试运行
至此,一个最简单的hello world的工程创建运行完成
7、打包部署
7.1 打包为可运行jar包
使用mvn package 进行打包
然后run ,运行成功后如下生成jar包
7.2 打包为传统的war包
当第2步中选择的打包方式为war时,执行7.1中mvn package时,生成的包就是war包
运行war包跟运行jar包一样,找到war包所在目录,注解运行war包
D:\new_tech\spring-suite-tool\workspace\workspace1\demo1\target>java -jar demo1-0.0.1-SNAPSHOT.war
访问服务接口: localhost:8080/greeting
2.代码实现连接数据实现Rest接口和Basic 基础认证
-
<dependency>
-
<groupId>org.projectlombok </groupId>
-
<artifactId>lombok </artifactId>
-
</dependency>
-
-
<!-- 使用MySQL数据库,并用Spring Data JPA来作为数据库访问 -->
-
<dependency>
-
<groupId>org.springframework.boot </groupId>
-
<artifactId>spring-boot-starter-data-jpa </artifactId>
-
</dependency>
-
<dependency>
-
<groupId>mysql </groupId>
-
<artifactId>mysql-connector-java </artifactId>
-
</dependency>
-
/*
-
* Filter实现简单的Http Basic 认证
-
*/
-
-
"httpBasicAuthorizedFilter", urlPatterns= "/user/*")(filterName =
-
public class HttpBasicAuthorizeFilter implements Filter {
-
-
public FilterRegistrationBean filterRegistrationBean() {
-
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
-
HttpBasicAuthorizeFilter httpBasicFilter = new HttpBasicAuthorizeFilter();
-
registrationBean.setFilter(httpBasicFilter);
-
List<String> urlPatterns = new ArrayList<String>();
-
urlPatterns.add( "/user/*");
-
registrationBean.setUrlPatterns(urlPatterns);
-
return registrationBean;
-
}
Authorization: Basic dGVzdDp0ZXN0
dGVzdDp0ZXN0 为 test:test 经过base64编码后的结果
如果未添加认证信息或者认证信息错误,返回没有权限的错误信息
当认证信息正确,返回请求结果
3.自定义Properties解析类和分布式Token JWT用户校验
1.自定义Properties解析类的使用规则
-
jwt.info.clientId=098f6bcd4621d373cade4e832627b4f6
-
jwt.info.base64Secret=MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=
-
jwt.info.name=restapiuser
-
jwt.info.expiresSecond=172800
-
package com.jay.properties;
-
-
import org.springframework.boot.context.properties.ConfigurationProperties;
-
/*
-
* 自定义配置文件的解析类
-
*/
-
"jwt.info", locations = "classpath:/config/jwt.properties")(prefix =
-
public class JwtInfo {
-
private String clientId;
-
private String base64Secret;
-
private String name;
-
private int expiresSecond;
-
public String getClientId() {
-
return clientId;
-
}
-
public void setClientId(String clientId) {
-
this.clientId = clientId;
-
}
-
public String getBase64Secret() {
-
return base64Secret;
-
}
-
public void setBase64Secret(String base64Secret) {
-
this.base64Secret = base64Secret;
-
}
-
public String getName() {
-
return name;
-
}
-
public void setName(String name) {
-
this.name = name;
-
}
-
public int getExpiresSecond() {
-
return expiresSecond;
-
}
-
public void setExpiresSecond(int expiresSecond) {
-
this.expiresSecond = expiresSecond;
-
}
-
-
}
-
package com.jay;
-
-
import org.springframework.boot.SpringApplication;
-
import org.springframework.boot.autoconfigure.SpringBootApplication;
-
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties.Jwt;
-
import org.springframework.boot.context.properties.EnableConfigurationProperties;
-
import org.springframework.boot.web.servlet.ServletComponentScan;
-
-
import com.jay.properties.JwtInfo;
-
-
-
//加载自定义的properties解析类(JwtInfo.class)
-
public class Demo1Application {
-
-
public static void main(String[] args) {
-
SpringApplication.run(Demo1Application.class, args);
-
}
-
}
-
package com.jay.controller;
-
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.web.bind.annotation.RequestMapping;
-
import org.springframework.web.bind.annotation.RequestMethod;
-
import org.springframework.web.bind.annotation.RestController;
-
-
import com.jay.properties.JwtInfo;
-
import com.jay.vo.ResultMsg;
-
import com.jay.vo.ResultStatusCode;
-
-
-
"/jwt")(
-
public class JwtInfoController {
-
-
-
private JwtInfo jwtInfo;
-
-
"/info", method = RequestMethod.GET)(value =
-
public Object getJwtInfo() {
-
return new ResultMsg<JwtInfo>( true, ResultStatusCode.OK.getErrorCode(), ResultStatusCode.OK.getErrorMsg(), jwtInfo);
-
}
-
}
5.效果展示
2.使用分布式token JWT进行用户认证
jwt(json web token)
用户发送按照约定,向服务端发送 Header、Payload 和 Signature,并包含认证信息(密码),验证通过后服务端返回一个token,之后用户使用该token作为登录凭证,适合于移动端和api
jwt使用流程
-
<!-- JWT Json Web Token 依赖 -->
-
<dependency>
-
<groupId>io.jsonwebtoken </groupId>
-
<artifactId>jjwt </artifactId>
-
<version>0.7.0 </version>
-
</dependency>
2.编写Jwt解析类和Jwt过滤器
-
package com.jay.util.jwt;
-
-
import java.security.Key;
-
import java.util.Date;
-
-
import javax.crypto.spec.SecretKeySpec;
-
import javax.xml.bind.DatatypeConverter;
-
-
import io.jsonwebtoken.Claims;
-
import io.jsonwebtoken.JwtBuilder;
-
import io.jsonwebtoken.Jwts;
-
import io.jsonwebtoken.SignatureAlgorithm;
-
-
/*
-
* 构造及解析jwt的工具类
-
*/
-
public class JwtHelper {
-
public static Claims parseJWT(String jsonWebToken, String base64Security){
-
try
-
{
-
Claims claims = Jwts.parser()
-
.setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
-
.parseClaimsJws(jsonWebToken).getBody();
-
return claims;
-
}
-
catch(Exception ex)
-
{
-
return null;
-
}
-
}
-
-
/**
-
* 生成token
-
*
-
* @author hetiewei
-
* @date 2016年10月18日 下午2:51:38
-
* @param name keyId
-
* @param userId
-
* @param role
-
* @param audience 接收者
-
* @param issuer 发行者
-
* @param TTLMillis 过期时间(毫秒)
-
* @param base64Security
-
* @return
-
*/
-
public static String createJWT(String name, String userId, String role,
-
String audience, String issuer, long TTLMillis, String base64Security)
-
{
-
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
-
-
long nowMillis = System.currentTimeMillis();
-
Date now = new Date(nowMillis);
-
-
//生成签名密钥
-
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
-
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
-
-
//添加构成JWT的参数
-
JwtBuilder builder = Jwts.builder().setHeaderParam( "typ", "JWT")
-
.claim( "role", role)
-
.claim( "unique_name", name)
-
.claim( "userid", userId)
-
.setIssuer(issuer)
-
.setAudience(audience)
-
.signWith(signatureAlgorithm, signingKey);
-
//添加Token过期时间
-
if (TTLMillis >= 0) {
-
long expMillis = nowMillis + TTLMillis;
-
Date exp = new Date(expMillis);
-
builder.setExpiration(exp).setNotBefore(now);
-
}
-
-
//生成JWT
-
return builder.compact();
-
}
-
}
-
package com.jay.filter;
-
-
import java.io.IOException;
-
-
import javax.servlet.Filter;
-
import javax.servlet.FilterChain;
-
import javax.servlet.FilterConfig;
-
import javax.servlet.ServletException;
-
import javax.servlet.ServletRequest;
-
import javax.servlet.ServletResponse;
-
import javax.servlet.http.HttpServletRequest;
-
import javax.servlet.http.HttpServletResponse;
-
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
-
-
import com.fasterxml.jackson.databind.ObjectMapper;
-
import com.jay.properties.JwtInfo;
-
import com.jay.util.jwt.JwtHelper;
-
import com.jay.vo.ResultMsg;
-
import com.jay.vo.ResultStatusCode;
-
-
/*
-
* 用于JWT认证的过滤器
-
*/
-
public class JwtAuthorizeFilter implements Filter{
-
-
/*
-
* 注入配置文件类
-
*/
-
-
private JwtInfo jwtInfo;
-
-
-
public void destroy() {
-
-
}
-
-
-
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
-
throws IOException, ServletException {
-
ResultMsg<Object> resultMsg;
-
HttpServletRequest httpRequest = (HttpServletRequest)request;
-
String auth = httpRequest.getHeader( "Authorization");
-
if ((auth != null) && (auth.length() > 7))
-
{
-
String HeadStr = auth.substring( 0, 6).toLowerCase();
-
if (HeadStr.compareTo( "bearer") == 0)
-
{
-
-
auth = auth.substring( 7, auth.length());
-
if (JwtHelper.parseJWT(auth, jwtInfo.getBase64Secret()) != null)
-
{
-
chain.doFilter(request, response);
-
return;
-
}
-
}
-
}
-
-
//验证不通过
-
HttpServletResponse httpResponse = (HttpServletResponse) response;
-
httpResponse.setCharacterEncoding( "UTF-8");
-
httpResponse.setContentType( "application/json; charset=utf-8");
-
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-
-
//将验证不通过的错误返回
-
ObjectMapper mapper = new ObjectMapper();
-
-
resultMsg = new ResultMsg<Object>( true, ResultStatusCode.INVALID_TOKEN.getErrorCode(), ResultStatusCode.INVALID_TOKEN.getErrorMsg(), null);
-
httpResponse.getWriter().write(mapper.writeValueAsString(resultMsg));
-
return;
-
}
-
-
-
public void init(FilterConfig filterConfig) throws ServletException {
-
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext( this, filterConfig.getServletContext());
-
}
-
-
}
-
package com.jay.config;
-
-
import java.util.ArrayList;
-
import java.util.List;
-
-
import org.springframework.boot.context.embedded.FilterRegistrationBean;
-
import org.springframework.context.annotation.Bean;
-
import org.springframework.context.annotation.Configuration;
-
-
import com.jay.filter.JwtAuthorizeFilter;
-
-
-
/*
-
* 注册jwt认证过滤器
-
*/
-
-
public class JwtConfig {
-
-
/*
-
* 注册过滤器类和过滤的url
-
*/
-
-
public FilterRegistrationBean basicFilterRegistrationBean(){
-
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
-
JwtAuthorizeFilter filter = new JwtAuthorizeFilter();
-
registrationBean.setFilter(filter);
-
-
List<String> urlPatterns = new ArrayList<>();
-
urlPatterns.add( "/user/*");
-
-
registrationBean.setUrlPatterns(urlPatterns);
-
return registrationBean;
-
}
-
}
4.Redis + Cookie 机制,进行验证码的校验
-
<!-- 整合redis -->
-
<dependency>
-
<groupId>org.springframework.boot </groupId>
-
<artifactId>spring-boot-starter-redis </artifactId>
-
</dependency>
-
<!-- 第三方验证码库 -->
-
<dependency>
-
<groupId>cn.apiclub.tool </groupId>
-
<artifactId>simplecaptcha </artifactId>
-
<version>1.2.2 </version>
-
</dependency>
-
##Redis配置
-
spring.redis.database=1
-
spring.redis.host=localhost
-
#spring.redis.password=password
-
spring.redis.port=6379
-
spring.redis.timeout=2000
-
spring.redis.pool.max-idle=8
-
spring.redis.pool.min-idle=0
-
spring.redis.pool.max-active=8
-
spring.redis.pool.max-wait=-1
-
package com.jay.config;
-
-
import org.springframework.context.annotation.Bean;
-
import org.springframework.context.annotation.Configuration;
-
import org.springframework.data.redis.connection.RedisConnectionFactory;
-
import org.springframework.data.redis.core.RedisTemplate;
-
import org.springframework.data.redis.core.StringRedisTemplate;
-
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
-
-
import com.fasterxml.jackson.annotation.JsonAutoDetect;
-
import com.fasterxml.jackson.annotation.PropertyAccessor;
-
import com.fasterxml.jackson.databind.ObjectMapper;
-
-
-
public class RedisConfig {
-
-
// 定义Redis模板
-
-
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
-
StringRedisTemplate template = new StringRedisTemplate(factory);
-
// 设置序列化工具, 这样缓存的Bean就不需要再试下Serializable接口
-
setSerrializer(template);
-
template.afterPropertiesSet();
-
return template;
-
}
-
-
// 设置序列化
-
private void setSerrializer(StringRedisTemplate template) {
-
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
-
ObjectMapper om = new ObjectMapper();
-
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
-
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
-
jackson2JsonRedisSerializer.setObjectMapper(om);
-
template.setValueSerializer(jackson2JsonRedisSerializer);
-
}
-
}
-
package com.jay.controller;
-
-
import java.io.ByteArrayOutputStream;
-
import java.io.IOException;
-
import java.util.UUID;
-
import java.util.concurrent.TimeUnit;
-
-
import javax.imageio.ImageIO;
-
import javax.servlet.http.Cookie;
-
import javax.servlet.http.HttpServletRequest;
-
import javax.servlet.http.HttpServletResponse;
-
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.data.redis.core.RedisTemplate;
-
import org.springframework.http.HttpRequest;
-
import org.springframework.http.MediaType;
-
import org.springframework.stereotype.Controller;
-
import org.springframework.web.bind.annotation.PathVariable;
-
import org.springframework.web.bind.annotation.RequestMapping;
-
import org.springframework.web.bind.annotation.RequestMethod;
-
import org.springframework.web.bind.annotation.ResponseBody;
-
-
import com.jay.util.CookieUtils;
-
import com.jay.vo.ResultMsg;
-
import com.jay.vo.ResultStatusCode;
-
-
import cn.apiclub.captcha.Captcha;
-
import cn.apiclub.captcha.backgrounds.GradiatedBackgroundProducer;
-
import cn.apiclub.captcha.gimpy.FishEyeGimpyRenderer;
-
import io.swagger.annotations.ApiOperation;
-
-
-
"/redis")(
-
public class RedisCaptchaController {
-
-
-
private RedisTemplate<String, String> redisTemplate;
-
-
private static int captchaExpires = 3 * 60; // 超时时间3min,验证码超时,自动冲redis中删除
-
private static int captchaW = 200;
-
private static int captchaH = 60;
-
private static String cookieName = "CaptchaCode";
-
-
"getcaptcha", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)(value =
-
public byte[] getCaptcha(HttpServletResponse response) {
-
// 生成验证码
-
String uuid = UUID.randomUUID().toString();
-
Captcha captcha = new Captcha.Builder(captchaW, captchaH).addText()
-
.addBackground( new GradiatedBackgroundProducer()).gimp( new FishEyeGimpyRenderer()).build();
-
-
// 将验证码以<key,value>形式缓存到redis
-
redisTemplate.opsForValue().set(uuid, captcha.getAnswer(), captchaExpires, TimeUnit.SECONDS);
-
-
// 将验证码key,及验证码的图片返回
-
Cookie cookie = new Cookie(cookieName, uuid);
-
response.addCookie(cookie);
-
ByteArrayOutputStream bao = new ByteArrayOutputStream();
-
try {
-
ImageIO.write(captcha.getImage(), "png", bao);
-
return bao.toByteArray();
-
} catch (IOException e) {
-
return null;
-
}
-
}
-
-
/*
-
* 说明:
-
* 1.captchaCode来自客户端的Cookie,在访问时,通过服务端设置
-
* 2.captcha是用户填写的验证码,将用户填写的验证码和通过captchaCode从redis中获取的验证码进行对比即可
-
*
-
*/
-
"验证码校验")(value =
-
"/captcha/check/{captcha}")(value =
-
-
public ResultMsg<Object> checkCaptcha(@PathVariable("captcha") String captcha, HttpServletRequest request){
-
-
String captchaCode = CookieUtils.getCookie(request, cookieName);
-
-
ResultMsg<Object> result;
-
-
try{
-
if (captcha == null)
-
{
-
throw new Exception();
-
}
-
-
//redis中查询验证码
-
String captchaValue = redisTemplate.opsForValue().get(captchaCode);
-
-
if (captchaValue == null) {
-
throw new Exception();
-
}
-
-
if (captchaValue.compareToIgnoreCase(captcha) != 0) {
-
throw new Exception();
-
}
-
-
//验证码匹配成功,redis则删除对应的验证码
-
redisTemplate.delete(captchaCode);
-
-
return new ResultMsg<Object>( true, ResultStatusCode.OK.getErrorCode(), ResultStatusCode.OK.getErrorMsg(), null);
-
-
} catch (Exception e) {
-
result = new ResultMsg<Object>( false, ResultStatusCode.INVALID_CAPTCHA.getErrorCode(), ResultStatusCode.INVALID_CAPTCHA.getErrorMsg(), null);
-
}
-
return result;
-
}
-
-
-
}