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;
- }
- }