您的位置:首页 > 数据库 > Redis

STS创建Spring Boot项目实战(Rest接口、数据库、用户认证、分布式Token JWT、Redis操作、日志和统一异常处理)

2018-07-10 18:49 1456 查看

1.项目创建


1、新建工程


2、选择打包方式,这边可以选择为打包为Jar包,或者传统的打包为War包

3、选择开发过程中使用到的技术,这边我选择的是Rest Repositories

4、新建测试用Controller

    文件内容如下

[java] view plain copy
  1. package com.xiaofangtech.example;  
  2.   
  3. import org.springframework.web.bind.annotation.RequestMapping;  
  4. import org.springframework.web.bind.annotation.RestController;  
  5.   
  6. @RestController  
  7. public class HelloController {  
  8.     @RequestMapping("/greeting")  
  9.     public String hello()  
  10.     {  
  11.         return "Hello world";  
  12.     }  
  13. }  

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 基础认证

0.引入pom依赖
  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. </dependency>
  5. <!-- 使用MySQL数据库,并用Spring Data JPA来作为数据库访问 -->
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-data-jpa</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>mysql</groupId>
  12. <artifactId>mysql-connector-java</artifactId>
  13. </dependency>




1.代码整体结构


2.注册Filter过滤器的两种方式:        1.在自定义的Filter上使用注解:           
  1. /*
  2. * Filter实现简单的Http Basic 认证
  3. */
  4. @Component
  5. @WebFilter(filterName = "httpBasicAuthorizedFilter", urlPatterns="/user/*")
  6. public class HttpBasicAuthorizeFilter implements Filter {

       2.在配置类中定义Filter
  1. @Bean
  2. public FilterRegistrationBean filterRegistrationBean() {
  3. FilterRegistrationBean registrationBean = new FilterRegistrationBean();
  4. HttpBasicAuthorizeFilter httpBasicFilter = new HttpBasicAuthorizeFilter();
  5. registrationBean.setFilter(httpBasicFilter);
  6. List<String> urlPatterns = new ArrayList<String>();
  7. urlPatterns.add("/user/*");
  8. registrationBean.setUrlPatterns(urlPatterns);
  9. return registrationBean;
  10. }


3.数据库和Rest接口操作效果展示:


4.过滤器效果展示  代码中固定用户名密码都为test,所以对接口进行请求时,需要添加以下认证头信息

Authorization: Basic dGVzdDp0ZXN0

dGVzdDp0ZXN0 为 test:test 经过base64编码后的结果


如果未添加认证信息或者认证信息错误,返回没有权限的错误信息




当认证信息正确,返回请求结果



3.自定义Properties解析类和分布式Token JWT用户校验

    1.自定义Properties解析类的使用规则

                  1.定义Properties配置文件   ---- jwt.properties                      
  1. jwt.info.clientId=098f6bcd4621d373cade4e832627b4f6
  2. jwt.info.base64Secret=MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=
  3. jwt.info.name=restapiuser
  4. jwt.info.expiresSecond=172800


                  2.自定义解析类                      ---- JwtInfo.java  指定配置文件地址和配置前缀,属性是前缀之后的名称
  1. package com.jay.properties;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. /*
  4. * 自定义配置文件的解析类
  5. */
  6. @ConfigurationProperties(prefix = "jwt.info", locations = "classpath:/config/jwt.properties")
  7. public class JwtInfo {
  8. private String clientId;
  9. private String base64Secret;
  10. private String name;
  11. private int expiresSecond;
  12. public String getClientId() {
  13. return clientId;
  14. }
  15. public void setClientId(String clientId) {
  16. this.clientId = clientId;
  17. }
  18. public String getBase64Secret() {
  19. return base64Secret;
  20. }
  21. public void setBase64Secret(String base64Secret) {
  22. this.base64Secret = base64Secret;
  23. }
  24. public String getName() {
  25. return name;
  26. }
  27. public void setName(String name) {
  28. this.name = name;
  29. }
  30. public int getExpiresSecond() {
  31. return expiresSecond;
  32. }
  33. public void setExpiresSecond(int expiresSecond) {
  34. this.expiresSecond = expiresSecond;
  35. }
  36. }



                  3.启动类或配置类中,指定自定义Properties解析类
  1. package com.jay;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties.Jwt;
  5. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  6. import org.springframework.boot.web.servlet.ServletComponentScan;
  7. import com.jay.properties.JwtInfo;
  8. @SpringBootApplication
  9. @EnableConfigurationProperties(JwtInfo.class) //加载自定义的properties解析类
  10. public class Demo1Application {
  11. public static void main(String[] args) {
  12. SpringApplication.run(Demo1Application.class, args);
  13. }
  14. }

               4.输出配置文件信息         ---- JwtInfoController.java
  1. package com.jay.controller;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.RequestMethod;
  5. import org.springframework.web.bind.annotation.RestController;
  6. import com.jay.properties.JwtInfo;
  7. import com.jay.vo.ResultMsg;
  8. import com.jay.vo.ResultStatusCode;
  9. @RestController
  10. @RequestMapping("/jwt")
  11. public class JwtInfoController {
  12. @Autowired
  13. private JwtInfo jwtInfo;
  14. @RequestMapping(value = "/info", method = RequestMethod.GET)
  15. public Object getJwtInfo() {
  16. return new ResultMsg<JwtInfo>(true, ResultStatusCode.OK.getErrorCode(), ResultStatusCode.OK.getErrorMsg(), jwtInfo);
  17. }
  18. }

               5.效果展示              

          2.使用分布式token  JWT进行用户认证


              

jwt(json web token)用户发送按照约定,向服务端发送 Header、Payload 和 Signature,并包含认证信息(密码),验证通过后服务端返回一个token,之后用户使用该token作为登录凭证,适合于移动端和api
jwt使用流程


              1.添加 JWT依赖
  1. <!-- JWT Json Web Token 依赖 -->
  2. <dependency>
  3. <groupId>io.jsonwebtoken</groupId>
  4. <artifactId>jjwt</artifactId>
  5. <version>0.7.0</version>
  6. </dependency>

             2.编写Jwt解析类和Jwt过滤器             
  1. package com.jay.util.jwt;
  2. import java.security.Key;
  3. import java.util.Date;
  4. import javax.crypto.spec.SecretKeySpec;
  5. import javax.xml.bind.DatatypeConverter;
  6. import io.jsonwebtoken.Claims;
  7. import io.jsonwebtoken.JwtBuilder;
  8. import io.jsonwebtoken.Jwts;
  9. import io.jsonwebtoken.SignatureAlgorithm;
  10. /*
  11. * 构造及解析jwt的工具类
  12. */
  13. public class JwtHelper {
  14. public static Claims parseJWT(String jsonWebToken, String base64Security){
  15. try
  16. {
  17. Claims claims = Jwts.parser()
  18. .setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
  19. .parseClaimsJws(jsonWebToken).getBody();
  20. return claims;
  21. }
  22. catch(Exception ex)
  23. {
  24. return null;
  25. }
  26. }
  27. /**
  28. * 生成token
  29. *
  30. * @author hetiewei
  31. * @date 2016年10月18日 下午2:51:38
  32. * @param name keyId
  33. * @param userId
  34. * @param role
  35. * @param audience 接收者
  36. * @param issuer 发行者
  37. * @param TTLMillis 过期时间(毫秒)
  38. * @param base64Security
  39. * @return
  40. */
  41. public static String createJWT(String name, String userId, String role,
  42. String audience, String issuer, long TTLMillis, String base64Security)
  43. {
  44. SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  45. long nowMillis = System.currentTimeMillis();
  46. Date now = new Date(nowMillis);
  47. //生成签名密钥
  48. byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
  49. Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
  50. //添加构成JWT的参数
  51. JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
  52. .claim("role", role)
  53. .claim("unique_name", name)
  54. .claim("userid", userId)
  55. .setIssuer(issuer)
  56. .setAudience(audience)
  57. .signWith(signatureAlgorithm, signingKey);
  58. //添加Token过期时间
  59. if (TTLMillis >= 0) {
  60. long expMillis = nowMillis + TTLMillis;
  61. Date exp = new Date(expMillis);
  62. builder.setExpiration(exp).setNotBefore(now);
  63. }
  64. //生成JWT
  65. return builder.compact();
  66. }
  67. }




  1. package com.jay.filter;
  2. import java.io.IOException;
  3. import javax.servlet.Filter;
  4. import javax.servlet.FilterChain;
  5. import javax.servlet.FilterConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.ServletRequest;
  8. import javax.servlet.ServletResponse;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.web.context.support.SpringBeanAutowiringSupport;
  13. import com.fasterxml.jackson.databind.ObjectMapper;
  14. import com.jay.properties.JwtInfo;
  15. import com.jay.util.jwt.JwtHelper;
  16. import com.jay.vo.ResultMsg;
  17. import com.jay.vo.ResultStatusCode;
  18. /*
  19. * 用于JWT认证的过滤器
  20. */
  21. public class JwtAuthorizeFilter implements Filter{
  22. /*
  23. * 注入配置文件类
  24. */
  25. @Autowired
  26. private JwtInfo jwtInfo;
  27. @Override
  28. public void destroy() {
  29. }
  30. @Override
  31. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  32. throws IOException, ServletException {
  33. ResultMsg<Object> resultMsg;
  34. HttpServletRequest httpRequest = (HttpServletRequest)request;
  35. String auth = httpRequest.getHeader("Authorization");
  36. if ((auth != null) && (auth.length() > 7))
  37. {
  38. String HeadStr = auth.substring(0, 6).toLowerCase();
  39. if (HeadStr.compareTo("bearer") == 0)
  40. {
  41. auth = auth.substring(7, auth.length());
  42. if (JwtHelper.parseJWT(auth, jwtInfo.getBase64Secret()) != null)
  43. {
  44. chain.doFilter(request, response);
  45. return;
  46. }
  47. }
  48. }
  49. //验证不通过
  50. HttpServletResponse httpResponse = (HttpServletResponse) response;
  51. httpResponse.setCharacterEncoding("UTF-8");
  52. httpResponse.setContentType("application/json; charset=utf-8");
  53. httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  54. //将验证不通过的错误返回
  55. ObjectMapper mapper = new ObjectMapper();
  56. resultMsg = new ResultMsg<Object>(true, ResultStatusCode.INVALID_TOKEN.getErrorCode(), ResultStatusCode.INVALID_TOKEN.getErrorMsg(), null);
  57. httpResponse.getWriter().write(mapper.writeValueAsString(resultMsg));
  58. return;
  59. }
  60. @Override
  61. public void init(FilterConfig filterConfig) throws ServletException {
  62. SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());
  63. }
  64. }







            3.在Jwt配置类中,添加过滤器             
  1. package com.jay.config;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.springframework.boot.context.embedded.FilterRegistrationBean;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import com.jay.filter.JwtAuthorizeFilter;
  8. /*
  9. * 注册jwt认证过滤器
  10. */
  11. @Configuration
  12. public class JwtConfig {
  13. /*
  14. * 注册过滤器类和过滤的url
  15. */
  16. @Bean
  17. public FilterRegistrationBean basicFilterRegistrationBean(){
  18. FilterRegistrationBean registrationBean = new FilterRegistrationBean();
  19. JwtAuthorizeFilter filter = new JwtAuthorizeFilter();
  20. registrationBean.setFilter(filter);
  21. List<String> urlPatterns = new ArrayList<>();
  22. urlPatterns.add("/user/*");
  23. registrationBean.setUrlPatterns(urlPatterns);
  24. return registrationBean;
  25. }
  26. }

                         4.效果展示:                       1. 获取token,传入用户认证信息




                    2.使用上面获取的token进行接口调用,     未使用token,获取token错误,或者token过期时


               3.使用正确的token时
                   
                    


特别注意:              JWT使用时,可以通过Cookie机制,自动的传递!!!

4.Redis + Cookie 机制,进行验证码的校验


1.添加redis和captcha库依赖
  1. <!-- 整合redis -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-redis</artifactId>
  5. </dependency>
  6. <!-- 第三方验证码库 -->
  7. <dependency>
  8. <groupId>cn.apiclub.tool</groupId>
  9. <artifactId>simplecaptcha</artifactId>
  10. <version>1.2.2</version>
  11. </dependency>


2.redis配置
  1. ##Redis配置
  2. spring.redis.database=1
  3. spring.redis.host=localhost
  4. #spring.redis.password=password
  5. spring.redis.port=6379
  6. spring.redis.timeout=2000
  7. spring.redis.pool.max-idle=8
  8. spring.redis.pool.min-idle=0
  9. spring.redis.pool.max-active=8
  10. spring.redis.pool.max-wait=-1


3.Redis配置类,实例化Redis模板
  1. package com.jay.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.data.redis.connection.RedisConnectionFactory;
  5. import org.springframework.data.redis.core.RedisTemplate;
  6. import org.springframework.data.redis.core.StringRedisTemplate;
  7. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  8. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  9. import com.fasterxml.jackson.annotation.PropertyAccessor;
  10. import com.fasterxml.jackson.databind.ObjectMapper;
  11. @Configuration
  12. public class RedisConfig {
  13. // 定义Redis模板
  14. @Bean
  15. public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
  16. StringRedisTemplate template = new StringRedisTemplate(factory);
  17. // 设置序列化工具, 这样缓存的Bean就不需要再试下Serializable接口
  18. setSerrializer(template);
  19. template.afterPropertiesSet();
  20. return template;
  21. }
  22. // 设置序列化
  23. private void setSerrializer(StringRedisTemplate template) {
  24. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  25. ObjectMapper om = new ObjectMapper();
  26. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  27. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  28. jackson2JsonRedisSerializer.setObjectMapper(om);
  29. template.setValueSerializer(jackson2JsonRedisSerializer);
  30. }
  31. }


4.Controller层操作代码
  1. package com.jay.controller;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.util.UUID;
  5. import java.util.concurrent.TimeUnit;
  6. import javax.imageio.ImageIO;
  7. import javax.servlet.http.Cookie;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.data.redis.core.RedisTemplate;
  12. import org.springframework.http.HttpRequest;
  13. import org.springframework.http.MediaType;
  14. import org.springframework.stereotype.Controller;
  15. import org.springframework.web.bind.annotation.PathVariable;
  16. import org.springframework.web.bind.annotation.RequestMapping;
  17. import org.springframework.web.bind.annotation.RequestMethod;
  18. import org.springframework.web.bind.annotation.ResponseBody;
  19. import com.jay.util.CookieUtils;
  20. import com.jay.vo.ResultMsg;
  21. import com.jay.vo.ResultStatusCode;
  22. import cn.apiclub.captcha.Captcha;
  23. import cn.apiclub.captcha.backgrounds.GradiatedBackgroundProducer;
  24. import cn.apiclub.captcha.gimpy.FishEyeGimpyRenderer;
  25. import io.swagger.annotations.ApiOperation;
  26. @Controller
  27. @RequestMapping("/redis")
  28. public class RedisCaptchaController {
  29. @Autowired
  30. private RedisTemplate<String, String> redisTemplate;
  31. private static int captchaExpires = 3 * 60; // 超时时间3min,验证码超时,自动冲redis中删除
  32. private static int captchaW = 200;
  33. private static int captchaH = 60;
  34. private static String cookieName = "CaptchaCode";
  35. @RequestMapping(value = "getcaptcha", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
  36. public @ResponseBody byte[] getCaptcha(HttpServletResponse response) {
  37. // 生成验证码
  38. String uuid = UUID.randomUUID().toString();
  39. Captcha captcha = new Captcha.Builder(captchaW, captchaH).addText()
  40. .addBackground(new GradiatedBackgroundProducer()).gimp(new FishEyeGimpyRenderer()).build();
  41. // 将验证码以<key,value>形式缓存到redis
  42. redisTemplate.opsForValue().set(uuid, captcha.getAnswer(), captchaExpires, TimeUnit.SECONDS);
  43. // 将验证码key,及验证码的图片返回
  44. Cookie cookie = new Cookie(cookieName, uuid);
  45. response.addCookie(cookie);
  46. ByteArrayOutputStream bao = new ByteArrayOutputStream();
  47. try {
  48. ImageIO.write(captcha.getImage(), "png", bao);
  49. return bao.toByteArray();
  50. } catch (IOException e) {
  51. return null;
  52. }
  53. }
  54. /*
  55. * 说明:
  56. * 1.captchaCode来自客户端的Cookie,在访问时,通过服务端设置
  57. * 2.captcha是用户填写的验证码,将用户填写的验证码和通过captchaCode从redis中获取的验证码进行对比即可
  58. *
  59. */
  60. @ApiOperation(value = "验证码校验")
  61. @RequestMapping(value = "/captcha/check/{captcha}")
  62. @ResponseBody
  63. public ResultMsg<Object> checkCaptcha(@PathVariable("captcha") String captcha, HttpServletRequest request){
  64. String captchaCode = CookieUtils.getCookie(request, cookieName);
  65. ResultMsg<Object> result;
  66. try{
  67. if (captcha == null)
  68. {
  69. throw new Exception();
  70. }
  71. //redis中查询验证码
  72. String captchaValue = redisTemplate.opsForValue().get(captchaCode);
  73. if (captchaValue == null) {
  74. throw new Exception();
  75. }
  76. if (captchaValue.compareToIgnoreCase(captcha) != 0) {
  77. throw new Exception();
  78. }
  79. //验证码匹配成功,redis则删除对应的验证码
  80. redisTemplate.delete(captchaCode);
  81. return new ResultMsg<Object>(true, ResultStatusCode.OK.getErrorCode(), ResultStatusCode.OK.getErrorMsg(), null);
  82. }catch (Exception e) {
  83. result = new ResultMsg<Object>(false, ResultStatusCode.INVALID_CAPTCHA.getErrorCode(), ResultStatusCode.INVALID_CAPTCHA.getErrorMsg(), null);
  84. }
  85. return result;
  86. }
  87. }


5.效果展示
1.访问生成验证码


2.验证验证码


项目源码下载:下载地址
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐