当前位置:   article > 正文

基于spring cloud的security权限认证(超详细)_springsecurity 登录权限验证

springsecurity 登录权限验证

目录

一、前言

二、项目结构

 三、搭建security

四、搭建common-utils

五、登录实现(user-service)

六、使用方式


一、前言

在网上找了很多基于spring cloud的security权限认证,但是大概都是网关内嵌security、security OAuth2的方式。这里给大家推荐另一种方式。以我的实战项目为例。

二、项目结构

这里父工程为pzhxy,大家可以自己定义,Security为子工程。

 三、搭建security

(1)依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-config</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-security</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>com.fasterxml.jackson.core</groupId>
  11. <artifactId>jackson-annotations</artifactId>
  12. </dependency>
  13. <dependency>
  14. <groupId>javax.servlet</groupId>
  15. <artifactId>javax.servlet-api</artifactId>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.springframework.data</groupId>
  19. <artifactId>spring-data-redis</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>io.jsonwebtoken</groupId>
  23. <artifactId>jjwt-api</artifactId>
  24. <version>0.10.7</version>
  25. <scope>compile</scope>
  26. </dependency>

 (2)SecurityConfig

  1. package com.pzhxy.security.config;
  2. import com.pzhxy.security.filter.JwtAuthenticationTokenFilter;
  3. import com.pzhxy.security.handler.AccessDeniedHandlerImpl;
  4. import com.pzhxy.security.handler.AuthenticationEntryPointImpl;
  5. import com.pzhxy.security.passwordencode.MyPasswordEncoder;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import org.springframework.security.authentication.AuthenticationManager;
  9. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  10. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  11. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  12. import org.springframework.security.config.http.SessionCreationPolicy;
  13. import org.springframework.security.crypto.password.PasswordEncoder;
  14. import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  15. import org.springframework.security.web.firewall.HttpFirewall;
  16. import org.springframework.security.web.firewall.StrictHttpFirewall;
  17. import javax.annotation.Resource;
  18. @Configuration
  19. @EnableGlobalMethodSecurity(prePostEnabled = true)
  20. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  21. @Resource
  22. private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
  23. @Resource
  24. private AuthenticationEntryPointImpl authenticationEntryPoint;
  25. @Resource
  26. private AccessDeniedHandlerImpl accessDeniedHandler;
  27. @Override
  28. protected void configure(HttpSecurity http) throws Exception {
  29. http.csrf().disable()
  30. .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  31. .and()
  32. .authorizeRequests()
  33. .antMatchers(
  34. "/",
  35. "/swagger-ui.html",
  36. "/user/login",
  37. "/user/hello",
  38. "/operate/**",
  39. "/webjars/**",
  40. "/v2/**",
  41. "/link/**",
  42. "/process/**",
  43. "/proProcess/**",
  44. "/project/**",
  45. "/mail/**",
  46. "/qiniuyun/**",
  47. "/comments/getpage/**",
  48. "/swagger-resources/**").permitAll()
  49. .anyRequest().authenticated();
  50. http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
  51. //认证授权失败处理
  52. http.exceptionHandling()
  53. .authenticationEntryPoint(authenticationEntryPoint)
  54. .accessDeniedHandler(accessDeniedHandler);
  55. //允许跨域
  56. http.cors();
  57. }
  58. @Bean
  59. public PasswordEncoder passwordEncoder(){
  60. return new MyPasswordEncoder();
  61. }
  62. @Bean
  63. public AuthenticationManager authenticationManagerBean() throws Exception {
  64. return super.authenticationManagerBean();
  65. }
  66. }

(3)LoginUser

注:User类定义在feign

  1. package com.pzhxy.security.domain;
  2. import com.baomidou.mybatisplus.annotation.TableField;
  3. import com.fasterxml.jackson.annotation.JsonIgnore;
  4. import com.pzhxy.feign.domain.User;
  5. import org.springframework.security.core.GrantedAuthority;
  6. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  7. import org.springframework.security.core.userdetails.UserDetails;
  8. import java.util.Collection;
  9. import java.util.List;
  10. import java.util.stream.Collectors;
  11. /**
  12. * 登录用户身份权限
  13. *
  14. * @author ruoyi
  15. */
  16. public class LoginUser implements UserDetails
  17. {
  18. private static final long serialVersionUID = 1L;
  19. /**
  20. * 登录时间
  21. */
  22. private Long loginTime;
  23. /**
  24. * 权限列表
  25. */
  26. private List<String> permissions;
  27. /**
  28. * 用户信息
  29. */
  30. private User user;
  31. @JsonIgnore
  32. @TableField(exist = false)
  33. private List<SimpleGrantedAuthority>authorities;
  34. //获取权限信息
  35. @Override
  36. public Collection<? extends GrantedAuthority> getAuthorities()
  37. {
  38. if(authorities!=null){
  39. return authorities;
  40. }
  41. //把permissios封装成对象
  42. authorities=permissions.stream()
  43. .map(SimpleGrantedAuthority::new)
  44. .collect(Collectors.toList());
  45. return authorities;
  46. }
  47. public LoginUser(){
  48. }
  49. public LoginUser(User user)
  50. {
  51. this.user = user;
  52. }
  53. @JsonIgnore
  54. @Override
  55. public String getPassword()
  56. {
  57. return user.getPassword();
  58. }
  59. @JsonIgnore
  60. @Override
  61. public String getUsername()
  62. {
  63. return user.getId();
  64. }
  65. /**
  66. * 账户是否未过期,过期无法验证
  67. */
  68. @JsonIgnore
  69. @Override
  70. public boolean isAccountNonExpired()
  71. {
  72. return true;
  73. }
  74. /**
  75. * 指定用户是否解锁,锁定的用户无法进行身份验证
  76. *
  77. * @return
  78. */
  79. @JsonIgnore
  80. @Override
  81. public boolean isAccountNonLocked()
  82. {
  83. return true;
  84. }
  85. /**
  86. * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
  87. *
  88. * @return
  89. */
  90. @JsonIgnore
  91. @Override
  92. public boolean isCredentialsNonExpired()
  93. {
  94. return true;
  95. }
  96. /**
  97. * 是否可用 ,禁用的用户不能身份验证
  98. *
  99. * @return
  100. */
  101. @JsonIgnore
  102. @Override
  103. public boolean isEnabled()
  104. {
  105. return true;
  106. }
  107. public Long getLoginTime()
  108. {
  109. return loginTime;
  110. }
  111. public void setLoginTime(Long loginTime)
  112. {
  113. this.loginTime = loginTime;
  114. }
  115. public List<String> getPermissions()
  116. {
  117. return permissions;
  118. }
  119. public void setPermissions(List<String> permissions)
  120. {
  121. this.permissions = permissions;
  122. }
  123. public User getUser()
  124. {
  125. return user;
  126. }
  127. public void setUser(User user)
  128. {
  129. this.user = user;
  130. }
  131. }

(4)JwtAuthenticationTokenFilter

  1. package com.pzhxy.security.filter;
  2. import com.pzhxy.redis.utils.JwtUtil;
  3. import com.pzhxy.redis.utils.RedisUtil;
  4. import com.pzhxy.security.domain.LoginUser;
  5. import io.jsonwebtoken.Claims;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  8. import org.springframework.security.core.context.SecurityContextHolder;
  9. import org.springframework.stereotype.Component;
  10. import org.springframework.util.StringUtils;
  11. import org.springframework.web.filter.OncePerRequestFilter;
  12. import javax.servlet.FilterChain;
  13. import javax.servlet.ServletException;
  14. import javax.servlet.http.HttpServletRequest;
  15. import javax.servlet.http.HttpServletResponse;
  16. import java.io.IOException;
  17. import java.util.Objects;
  18. @Component
  19. public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
  20. @Autowired
  21. private RedisUtil redisUtil;
  22. @Override
  23. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
  24. String token = request.getHeader("Authorization");
  25. if(!StringUtils.hasText(token)){
  26. filterChain.doFilter(request,response);
  27. return;
  28. }
  29. String userid;
  30. try {
  31. //JWT解析token,截取userID
  32. Claims claims= JwtUtil.getClaim(token);
  33. userid=claims.get("userId").toString();
  34. }catch (Exception e){
  35. e.printStackTrace();
  36. throw new RuntimeException("token非法");
  37. }
  38. String redisKey="login:"+userid;
  39. LoginUser loginUser =(LoginUser)redisUtil.get(redisKey);
  40. System.out.println(loginUser);
  41. if(Objects.isNull(loginUser)){
  42. throw new RuntimeException("用户未登录");
  43. }
  44. //存入SecurityContextHolder,获取权限信息
  45. UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(loginUser,null, loginUser.getAuthorities());
  46. SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
  47. filterChain.doFilter(request,response);
  48. }
  49. }

(5)AccessDeniedHandlerImpl

  1. package com.pzhxy.security.handler;
  2. import com.alibaba.fastjson.JSON;
  3. import com.pzhxy.constant.result.ResultBean;
  4. import org.springframework.http.HttpStatus;
  5. import org.springframework.security.access.AccessDeniedException;
  6. import org.springframework.security.web.access.AccessDeniedHandler;
  7. import org.springframework.stereotype.Component;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.IOException;
  12. /***
  13. * 授权失败处理
  14. *@Date:2022/6/4
  15. * @Author: Liu
  16. */
  17. @Component
  18. public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
  19. @Override
  20. public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
  21. ResultBean result=new ResultBean(HttpStatus.FORBIDDEN.value(),"您的权限不足");
  22. String json= JSON.toJSONString(result);
  23. response.setStatus(200);
  24. response.setContentType("application/json");
  25. response.setCharacterEncoding("utf-8");
  26. response.getWriter().print(json);
  27. }
  28. }

(6)AuthenticationEntryPointImpl

  1. package com.pzhxy.security.handler;
  2. import com.alibaba.fastjson.JSON;
  3. import com.pzhxy.constant.result.ResultBean;
  4. import org.springframework.http.HttpStatus;
  5. import org.springframework.security.core.AuthenticationException;
  6. import org.springframework.security.web.AuthenticationEntryPoint;
  7. import org.springframework.stereotype.Component;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.IOException;
  12. /**
  13. * 认证失败处理
  14. *@Date:2022/6/4
  15. * @Author: Liu
  16. */
  17. @Component
  18. public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
  19. @Override
  20. public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
  21. ResultBean result=new ResultBean(HttpStatus.UNAUTHORIZED.value(),"用户认证失败请查询登录");
  22. String json= JSON.toJSONString(result);
  23. response.setStatus(200);
  24. response.setContentType("application/json");
  25. response.setCharacterEncoding("utf-8");
  26. response.getWriter().print(json);
  27. }
  28. }

(7)MyPasswordEncoder(自定义加密方式)

  1. package com.pzhxy.security.passwordencode;
  2. import com.pzhxy.security.utils.MD5Util;
  3. import org.springframework.security.crypto.password.PasswordEncoder;
  4. import java.util.Objects;
  5. public class MyPasswordEncoder implements PasswordEncoder {
  6. @Override
  7. public String encode(CharSequence charSequence) {
  8. return MD5Util.encode((String) charSequence);
  9. }
  10. //加密验证方法
  11. @Override
  12. public boolean matches(CharSequence rawPassword, String encodedPassword) {
  13. return Objects.equals(rawPassword, encodedPassword);
  14. }
  15. }

(8)MD5Util(MD5加密方式)

  1. package com.pzhxy.security.utils;
  2. import java.security.MessageDigest;
  3. /**
  4. * @author 言曌
  5. * @date 2018/2/9 下午6:11
  6. */
  7. public class MD5Util {
  8. private static final String SALT = "liuyanzhao.com";
  9. /**
  10. * MD5加盐加密
  11. *
  12. * @param password
  13. * @return
  14. */
  15. public static String encode(String password) {
  16. password = password + SALT;
  17. MessageDigest md5 = null;
  18. try {
  19. md5 = MessageDigest.getInstance("MD5");
  20. } catch (Exception e) {
  21. throw new RuntimeException(e);
  22. }
  23. char[] charArray = password.toCharArray();
  24. byte[] byteArray = new byte[charArray.length];
  25. for (int i = 0; i < charArray.length; i++)
  26. byteArray[i] = (byte) charArray[i];
  27. byte[] md5Bytes = md5.digest(byteArray);
  28. StringBuffer hexValue = new StringBuffer();
  29. for (int i = 0; i < md5Bytes.length; i++) {
  30. int val = ((int) md5Bytes[i]) & 0xff;
  31. if (val < 16) {
  32. hexValue.append("0");
  33. }
  34. hexValue.append(Integer.toHexString(val));
  35. }
  36. return hexValue.toString();
  37. }
  38. public static void main(String[] args) {
  39. String hashPass = MD5Util.encode("123456");
  40. System.out.println(MD5Util.encode("123456"));//08dc78d36d1512e5a81ef05b01a37860
  41. System.out.println("08dc78d36d1512e5a81ef05b01a37860".equals(hashPass));//true
  42. }
  43. }

四、搭建common-utils

(1)common-utils结构

 (2)搭建feign

这里只需要自定义的User类,大家按自己需求写。

依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-openfeign</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.example</groupId>
  8. <artifactId>common-base</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. <scope>compile</scope>
  11. </dependency>
  12. </dependencies>

(3)搭建common-base

这里只需要ResultBean封装结果,大家可以自己定义

  1. package com.pzhxy.constant.result;
  2. import lombok.Data;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. /***
  6. * 返回结果的统一封装
  7. */
  8. @Data
  9. public class ResultBean<T> {
  10. private Boolean success; //是否成功
  11. private Integer code; //返回状态码
  12. private String message; //返回消息提示
  13. private T data;
  14. private ResultBean(){}
  15. public static ResultBean ok(){
  16. ResultBean r = new ResultBean();
  17. r.setSuccess(true);
  18. r.setCode(ResultCode.SUCCESS);
  19. r.setMessage("成功");
  20. return r;
  21. }
  22. public static ResultBean error(){
  23. ResultBean r = new ResultBean();
  24. r.setSuccess(false);
  25. r.setCode(ResultCode.ERROR);
  26. r.setMessage("失败");
  27. return r;
  28. }
  29. public ResultBean(Integer code, String message) {
  30. this.code = code;
  31. this.message = message;
  32. }
  33. public ResultBean success(Boolean success){
  34. this.setSuccess(success);
  35. return this;
  36. }
  37. public ResultBean message(String message){
  38. this.setMessage(message);
  39. return this;
  40. }
  41. public ResultBean code(Integer code){
  42. this.setCode(code);
  43. return this;
  44. }
  45. public ResultBean(Integer code, String message, T data) {
  46. this.code = code;
  47. this.message = message;
  48. this.data = data;
  49. }
  50. }

依赖

  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.slf4j</groupId>
  7. <artifactId>slf4j-api</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>org.springframework</groupId>
  11. <artifactId>spring-web</artifactId>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-autoconfigure</artifactId>
  16. </dependency>

(4)搭建redis

  1. <dependencies>
  2. <!-- redis-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-data-redis</artifactId>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.fasterxml.jackson.datatype</groupId>
  9. <artifactId>jackson-datatype-jsr310</artifactId>
  10. </dependency>
  11. <!-- JWT-->
  12. <dependency>
  13. <groupId>io.jsonwebtoken</groupId>
  14. <artifactId>jjwt-api</artifactId>
  15. <version>0.10.7</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>io.jsonwebtoken</groupId>
  19. <artifactId>jjwt-impl</artifactId>
  20. <version>0.10.7</version>
  21. <scope>runtime</scope>
  22. </dependency>
  23. <dependency>
  24. <groupId>io.jsonwebtoken</groupId>
  25. <artifactId>jjwt-jackson</artifactId>
  26. <version>0.10.7</version>
  27. <scope>runtime</scope>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.apache.commons</groupId>
  31. <artifactId>commons-pool2</artifactId>
  32. <version>2.2</version>
  33. </dependency>
  34. </dependencies>
  1. package com.pzhxy.redis.config;
  2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  3. import com.fasterxml.jackson.annotation.PropertyAccessor;
  4. import com.fasterxml.jackson.databind.ObjectMapper;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.data.redis.connection.RedisConnectionFactory;
  8. import org.springframework.data.redis.core.RedisTemplate;
  9. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  10. import org.springframework.data.redis.serializer.StringRedisSerializer;
  11. import java.net.UnknownHostException;
  12. @Configuration
  13. public class RedisConfig {
  14. //编写自己的redisTemplate
  15. @Bean
  16. @SuppressWarnings("all")
  17. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
  18. // 为了开发方便,直接使用<String, Object>
  19. RedisTemplate<String, Object> template = new RedisTemplate();
  20. template.setConnectionFactory(redisConnectionFactory);
  21. // Json 配置序列化
  22. // 使用 jackson 解析任意的对象
  23. Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
  24. // 使用 objectMapper 进行转义
  25. ObjectMapper objectMapper = new ObjectMapper();
  26. objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  27. objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  28. jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
  29. // String 的序列化
  30. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
  31. // key 采用 String 的序列化方式
  32. template.setKeySerializer(stringRedisSerializer);
  33. // Hash 的 key 采用 String 的序列化方式
  34. template.setHashKeySerializer(stringRedisSerializer);
  35. // value 采用 jackson 的序列化方式
  36. template.setValueSerializer(jackson2JsonRedisSerializer);
  37. // Hash 的 value 采用 jackson 的序列化方式
  38. template.setHashValueSerializer(jackson2JsonRedisSerializer);
  39. // 把所有的配置 set 进 template
  40. template.afterPropertiesSet();
  41. return template;
  42. }
  43. }
  1. package com.pzhxy.redis.utils;
  2. import io.jsonwebtoken.*;
  3. import io.jsonwebtoken.security.Keys;
  4. import javax.crypto.SecretKey;
  5. import java.text.SimpleDateFormat;
  6. import java.util.Base64;
  7. import java.util.Date;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. /**
  11. * @author:Tlimited
  12. *
  13. */
  14. public class JwtUtil {
  15. private static final long EXPIRE = 60 * 1000 * 60 * 24; //过期时间
  16. //密钥,动态生成的密钥
  17. // public static final SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
  18. //固定秘钥,非动态
  19. public static String key = "LiuYangdejavawebtuanduidediyigexiangmujijiangwancheng";
  20. /**
  21. * 生成token
  22. *
  23. * @param claims 要传送消息map
  24. * @return
  25. */
  26. public static String generate(Map<String,Object> claims) {
  27. Date nowDate = new Date();
  28. //过期时间,设定为一分钟
  29. Date expireDate = new Date(System.currentTimeMillis() + EXPIRE);
  30. //头部信息,可有可无
  31. Map<String, Object> header = new HashMap<>(2);
  32. header.put("typ", "jwt");
  33. //更强的密钥,JDK11起才能用
  34. // KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
  35. // PrivateKey key1 = keyPair.getPrivate(); // 私钥
  36. //PublicKey key2 = keyPair.getPublic(); //公钥
  37. return Jwts.builder().setHeader(header)
  38. // .setSubject("weimi")//主题
  39. // .setIssuer("weimi") //发送方
  40. .setClaims(claims) //自定义claims
  41. .setIssuedAt(nowDate)//当前时间
  42. .setExpiration(expireDate) //过期时间
  43. .signWith(SignatureAlgorithm.HS256,key)//签名算法和key
  44. .compact();
  45. }
  46. /**
  47. * 生成token
  48. * @param header 传入头部信息map
  49. * @param claims 要传送消息map
  50. * @return
  51. */
  52. public static String generate( Map<String, Object> header,Map<String,Object> claims) {
  53. Date nowDate = new Date();
  54. //过期时间,设定为一分钟
  55. Date expireDate = new Date(System.currentTimeMillis() + EXPIRE);
  56. return Jwts.builder().setHeader(header)
  57. // .setSubject("weimi")//主题
  58. // .setIssuer("weimi") //发送方
  59. .setClaims(claims) //自定义claims
  60. .setIssuedAt(nowDate)//当前时间
  61. .setExpiration(expireDate) //过期时间
  62. .signWith(SignatureAlgorithm.HS256,key)//签名算法和key
  63. .compact();
  64. }
  65. /**
  66. * 校验是不是jwt签名
  67. * @param token
  68. * @return
  69. */
  70. public static boolean isSigned(String token){
  71. return Jwts.parser()
  72. .setSigningKey(key)
  73. .isSigned(token);
  74. }
  75. /**
  76. * 校验签名是否正确
  77. * @param token
  78. * @return
  79. */
  80. public static boolean verify(String token){
  81. try {
  82. Jwts.parser()
  83. .setSigningKey(key)
  84. .parseClaimsJws(token);
  85. return true;
  86. }catch (JwtException e){
  87. System.out.println(e.getMessage());
  88. return false;
  89. }
  90. }
  91. /**
  92. * 获取payload 部分内容(即要传的信息)
  93. * 使用方法:如获取userId:getClaim(token).get("userId");
  94. * @param token
  95. * @return
  96. */
  97. public static Claims getClaim(String token) {
  98. Claims claims = null;
  99. try {
  100. claims = Jwts.parser()
  101. .setSigningKey(key)
  102. .parseClaimsJws(token)
  103. .getBody();
  104. } catch (Exception e) {
  105. e.printStackTrace();
  106. }
  107. return claims;
  108. }
  109. /**
  110. * 获取头部信息map
  111. * 使用方法 : getHeader(token).get("alg");
  112. * @param token
  113. * @return
  114. */
  115. public static JwsHeader getHeader(String token) {
  116. JwsHeader header = null;
  117. try {
  118. header = Jwts.parser()
  119. .setSigningKey(key)
  120. .parseClaimsJws(token)
  121. .getHeader();
  122. } catch (Exception e) {
  123. e.printStackTrace();
  124. }
  125. return header;
  126. }
  127. /**
  128. * 获取jwt发布时间
  129. */
  130. public static Date getIssuedAt(String token) {
  131. return getClaim(token).getIssuedAt();
  132. }
  133. /**
  134. * 获取jwt失效时间
  135. */
  136. public static Date getExpiration(String token) {
  137. return getClaim(token).getExpiration();
  138. }
  139. /**
  140. * 验证token是否失效
  141. *
  142. * @param token
  143. * @return true:过期 false:没过期
  144. */
  145. public static boolean isExpired(String token) {
  146. try {
  147. final Date expiration = getExpiration(token);
  148. return expiration.before(new Date());
  149. } catch (ExpiredJwtException expiredJwtException) {
  150. return true;
  151. }
  152. }
  153. /**
  154. * 直接Base64解密获取header内容
  155. * @param token
  156. * @return
  157. */
  158. public static String getHeaderByBase64(String token){
  159. String header = null;
  160. if (isSigned(token)){
  161. try {
  162. byte[] header_byte = Base64.getDecoder().decode(token.split("\\.")[0]);
  163. header = new String(header_byte);
  164. }catch (Exception e){
  165. e.printStackTrace();
  166. return null;
  167. }
  168. }
  169. return header;
  170. }
  171. /**
  172. * 直接Base64解密获取payload内容
  173. * @param token
  174. * @return
  175. */
  176. public static String getPayloadByBase64(String token){
  177. String payload = null;
  178. if (isSigned(token)) {
  179. try {
  180. byte[] payload_byte = Base64.getDecoder().decode(token.split("\\.")[1]);
  181. payload = new String(payload_byte);
  182. }catch (Exception e){
  183. e.printStackTrace();
  184. return null;
  185. }
  186. }
  187. return payload;
  188. }
  189. public static void main(String[] args) {
  190. //用户自定义信息claims
  191. Map<String,Object> map = new HashMap<>();
  192. map.put("userId","admin");
  193. String token = generate(map);
  194. System.out.println(token);
  195. System.out.println("claim:" + getClaim(token).get("userId"));
  196. System.out.println("header:" + getHeader(token));
  197. // System.out.println(getIssuedAt(token));
  198. Claims claims=getClaim(token);
  199. // System.out.println(getHeaderByBase64(token));
  200. System.out.println(getPayloadByBase64(token));
  201. SimpleDateFormat sdf=new SimpleDateFormat("yyyy‐MM‐dd hh:mm:ss");
  202. System.out.println("签发时间:"+sdf.format(claims.getIssuedAt()));
  203. System.out.println("过期时间:"+sdf.format(claims.getExpiration()));
  204. System.out.println("当前时间:"+sdf.format(new Date()) );
  205. }
  206. }
  1. package com.pzhxy.redis.utils;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.data.redis.core.RedisTemplate;
  4. import org.springframework.stereotype.Component;
  5. import org.springframework.util.CollectionUtils;
  6. import javax.annotation.Resource;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Set;
  10. import java.util.concurrent.TimeUnit;
  11. /**
  12. * @author Zly
  13. * @date 2019/8/7 0007 17:30
  14. */
  15. @Component
  16. public class RedisUtil {
  17. @Resource
  18. private RedisTemplate<String, Object> redisTemplate;
  19. // =============================common============================
  20. /**
  21. * 指定缓存失效时间
  22. * @param key 键
  23. * @param time 时间(秒)
  24. * @return
  25. */
  26. public boolean expire(String key, long time) {
  27. try {
  28. if (time > 0) {
  29. redisTemplate.expire(key, time, TimeUnit.SECONDS);
  30. }
  31. return true;
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. return false;
  35. }
  36. }
  37. /**
  38. * 根据key 获取过期时间
  39. * @param key 键 不能为null
  40. * @return 时间(秒) 返回0代表为永久有效
  41. */
  42. public long getExpire(String key) {
  43. return redisTemplate.getExpire(key, TimeUnit.SECONDS);
  44. }
  45. /**
  46. * 判断key是否存在
  47. * @param key 键
  48. * @return true 存在 false不存在
  49. */
  50. public boolean hasKey(String key) {
  51. try {
  52. return redisTemplate.hasKey(key);
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. return false;
  56. }
  57. }
  58. /**
  59. * 删除缓存
  60. * @param key 可以传一个值 或多个
  61. */
  62. @SuppressWarnings("unchecked")
  63. public void del(String... key) {
  64. if (key != null && key.length > 0) {
  65. if (key.length == 1) {
  66. redisTemplate.delete(key[0]);
  67. } else {
  68. redisTemplate.delete(CollectionUtils.arrayToList(key));
  69. }
  70. }
  71. }
  72. // ============================String=============================
  73. /**
  74. * 普通缓存获取
  75. * @param key 键
  76. * @return
  77. */
  78. public Object get(String key) {
  79. return key == null ? null : redisTemplate.opsForValue().get(key);
  80. }
  81. /**
  82. * 普通缓存放入
  83. * @param key 键
  84. * @param value 值
  85. * @return true成功 false失败
  86. */
  87. public boolean set(String key, Object value) {
  88. try {
  89. redisTemplate.opsForValue().set(key, value);
  90. return true;
  91. } catch (Exception e) {
  92. e.printStackTrace();
  93. return false;
  94. }
  95. }
  96. /**
  97. * 普通缓存放入并设置时间
  98. * @param key 键
  99. * @param value 值
  100. * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
  101. * @return true成功 false 失败
  102. */
  103. public boolean set(String key, Object value, long time) {
  104. try {
  105. if (time > 0) {
  106. redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
  107. } else {
  108. set(key, value);
  109. }
  110. return true;
  111. } catch (Exception e) {
  112. e.printStackTrace();
  113. return false;
  114. }
  115. }
  116. /**
  117. * 递增
  118. * @param key 键
  119. * @param delta 要增加几(大于0)
  120. * @return
  121. */
  122. public long incr(String key, long delta) {
  123. if (delta < 0) {
  124. throw new RuntimeException("递增因子必须大于0");
  125. }
  126. return redisTemplate.opsForValue().increment(key, delta);
  127. }
  128. /**
  129. * 递减
  130. * @param key 键
  131. * @param delta 要减少几(小于0)
  132. * @return
  133. */
  134. public long decr(String key, long delta) {
  135. if (delta < 0) {
  136. throw new RuntimeException("递减因子必须大于0");
  137. }
  138. return redisTemplate.opsForValue().increment(key, -delta);
  139. }
  140. // ================================Map=================================
  141. /**
  142. * HashGet
  143. * @param key 键 不能为null
  144. * @param item 项 不能为null
  145. * @return
  146. */
  147. public Object hget(String key, String item) {
  148. return redisTemplate.opsForHash().get(key, item);
  149. }
  150. /**
  151. * 获取hashKey对应的所有键值
  152. * @param key 键
  153. * @return 对应的多个键值
  154. */
  155. public Map<Object, Object> hmget(String key) {
  156. return redisTemplate.opsForHash().entries(key);
  157. }
  158. /**
  159. * HashSet
  160. * @param key 键
  161. * @param map 对应多个键值
  162. * @return true 成功 false 失败
  163. */
  164. public boolean hmset(String key, Map<String, Object> map) {
  165. try {
  166. redisTemplate.opsForHash().putAll(key, map);
  167. return true;
  168. } catch (Exception e) {
  169. e.printStackTrace();
  170. return false;
  171. }
  172. }
  173. /**
  174. * HashSet 并设置时间
  175. * @param key 键
  176. * @param map 对应多个键值
  177. * @param time 时间(秒)
  178. * @return true成功 false失败
  179. */
  180. public boolean hmset(String key, Map<String, Object> map, long time) {
  181. try {
  182. redisTemplate.opsForHash().putAll(key, map);
  183. if (time > 0) {
  184. expire(key, time);
  185. }
  186. return true;
  187. } catch (Exception e) {
  188. e.printStackTrace();
  189. return false;
  190. }
  191. }
  192. /**
  193. * 向一张hash表中放入数据,如果不存在将创建
  194. * @param key 键
  195. * @param item 项
  196. * @param value 值
  197. * @return true 成功 false失败
  198. */
  199. public boolean hset(String key, String item, Object value) {
  200. try {
  201. redisTemplate.opsForHash().put(key, item, value);
  202. return true;
  203. } catch (Exception e) {
  204. e.printStackTrace();
  205. return false;
  206. }
  207. }
  208. /**
  209. * 向一张hash表中放入数据,如果不存在将创建
  210. * @param key 键
  211. * @param item 项
  212. * @param value 值
  213. * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
  214. * @return true 成功 false失败
  215. */
  216. public boolean hset(String key, String item, Object value, long time) {
  217. try {
  218. redisTemplate.opsForHash().put(key, item, value);
  219. if (time > 0) {
  220. expire(key, time);
  221. }
  222. return true;
  223. } catch (Exception e) {
  224. e.printStackTrace();
  225. return false;
  226. }
  227. }
  228. /**
  229. * 删除hash表中的值
  230. * @param key 键 不能为null
  231. * @param item 项 可以使多个 不能为null
  232. */
  233. public void hdel(String key, Object... item) {
  234. redisTemplate.opsForHash().delete(key, item);
  235. }
  236. /**
  237. * 判断hash表中是否有该项的值
  238. * @param key 键 不能为null
  239. * @param item 项 不能为null
  240. * @return true 存在 false不存在
  241. */
  242. public boolean hHasKey(String key, String item) {
  243. return redisTemplate.opsForHash().hasKey(key, item);
  244. }
  245. /**
  246. * hash递增 如果不存在,就会创建一个 并把新增后的值返回
  247. * @param key 键
  248. * @param item 项
  249. * @param by 要增加几(大于0)
  250. * @return
  251. */
  252. public double hincr(String key, String item, double by) {
  253. return redisTemplate.opsForHash().increment(key, item, by);
  254. }
  255. /**
  256. * hash递减
  257. * @param key 键
  258. * @param item 项
  259. * @param by 要减少记(小于0)
  260. * @return
  261. */
  262. public double hdecr(String key, String item, double by) {
  263. return redisTemplate.opsForHash().increment(key, item, -by);
  264. }
  265. // ============================set=============================
  266. /**
  267. * 根据key获取Set中的所有值
  268. * @param key 键
  269. * @return
  270. */
  271. public Set<Object> sGet(String key) {
  272. try {
  273. return redisTemplate.opsForSet().members(key);
  274. } catch (Exception e) {
  275. e.printStackTrace();
  276. return null;
  277. }
  278. }
  279. /**
  280. * 根据value从一个set中查询,是否存在
  281. * @param key 键
  282. * @param value 值
  283. * @return true 存在 false不存在
  284. */
  285. public boolean sHasKey(String key, Object value) {
  286. try {
  287. return redisTemplate.opsForSet().isMember(key, value);
  288. } catch (Exception e) {
  289. e.printStackTrace();
  290. return false;
  291. }
  292. }
  293. /**
  294. * 将数据放入set缓存
  295. * @param key 键
  296. * @param values 值 可以是多个
  297. * @return 成功个数
  298. */
  299. public long sSet(String key, Object... values) {
  300. try {
  301. return redisTemplate.opsForSet().add(key, values);
  302. } catch (Exception e) {
  303. e.printStackTrace();
  304. return 0;
  305. }
  306. }
  307. /**
  308. * 将set数据放入缓存
  309. * @param key 键
  310. * @param time 时间(秒)
  311. * @param values 值 可以是多个
  312. * @return 成功个数
  313. */
  314. public long sSetAndTime(String key, long time, Object... values) {
  315. try {
  316. Long count = redisTemplate.opsForSet().add(key, values);
  317. if (time > 0) {
  318. expire(key, time);
  319. }
  320. return count;
  321. } catch (Exception e) {
  322. e.printStackTrace();
  323. return 0;
  324. }
  325. }
  326. /**
  327. * 获取set缓存的长度
  328. * @param key 键
  329. * @return
  330. */
  331. public long sGetSetSize(String key) {
  332. try {
  333. return redisTemplate.opsForSet().size(key);
  334. } catch (Exception e) {
  335. e.printStackTrace();
  336. return 0;
  337. }
  338. }
  339. /**
  340. * 移除值为value的
  341. * @param key 键
  342. * @param values 值 可以是多个
  343. * @return 移除的个数
  344. */
  345. public long setRemove(String key, Object... values) {
  346. try {
  347. Long count = redisTemplate.opsForSet().remove(key, values);
  348. return count;
  349. } catch (Exception e) {
  350. e.printStackTrace();
  351. return 0;
  352. }
  353. }
  354. // ===============================list=================================
  355. /**
  356. * 获取list缓存的内容
  357. * @param key 键
  358. * @param start 开始
  359. * @param end 结束 0 到 -1代表所有值
  360. * @return
  361. */
  362. public List<Object> lGet(String key, long start, long end) {
  363. try {
  364. return redisTemplate.opsForList().range(key, start, end);
  365. } catch (Exception e) {
  366. e.printStackTrace();
  367. return null;
  368. }
  369. }
  370. /**
  371. * 获取list缓存的长度
  372. * @param key 键
  373. * @return
  374. */
  375. public long lGetListSize(String key) {
  376. try {
  377. return redisTemplate.opsForList().size(key);
  378. } catch (Exception e) {
  379. e.printStackTrace();
  380. return 0;
  381. }
  382. }
  383. /**
  384. * 通过索引 获取list中的值
  385. * @param key 键
  386. * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
  387. * @return
  388. */
  389. public Object lGetIndex(String key, long index) {
  390. try {
  391. return redisTemplate.opsForList().index(key, index);
  392. } catch (Exception e) {
  393. e.printStackTrace();
  394. return null;
  395. }
  396. }
  397. /**
  398. * 将list放入缓存
  399. * @param key 键
  400. * @param value 值
  401. * @return
  402. */
  403. public boolean lSet(String key, Object value) {
  404. try {
  405. redisTemplate.opsForList().rightPush(key, value);
  406. return true;
  407. } catch (Exception e) {
  408. e.printStackTrace();
  409. return false;
  410. }
  411. }
  412. /**
  413. * 将list放入缓存
  414. * @param key 键
  415. * @param value 值
  416. * @param time 时间(秒)
  417. * @return
  418. */
  419. public boolean lSet(String key, Object value, long time) {
  420. try {
  421. redisTemplate.opsForList().rightPush(key, value);
  422. if (time > 0) {
  423. expire(key, time);
  424. }
  425. return true;
  426. } catch (Exception e) {
  427. e.printStackTrace();
  428. return false;
  429. }
  430. }
  431. /**
  432. * 将list放入缓存
  433. * @param key 键
  434. * @param value 值
  435. * @return
  436. */
  437. public boolean lSet(String key, List<Object> value) {
  438. try {
  439. redisTemplate.opsForList().rightPushAll(key, value);
  440. return true;
  441. } catch (Exception e) {
  442. e.printStackTrace();
  443. return false;
  444. }
  445. }
  446. /**
  447. * 将list放入缓存
  448. *
  449. * @param key 键
  450. * @param value 值
  451. * @param time 时间(秒)
  452. * @return
  453. */
  454. public boolean lSet(String key, List<Object> value, long time) {
  455. try {
  456. redisTemplate.opsForList().rightPushAll(key, value);
  457. if (time > 0) {
  458. expire(key, time);
  459. }
  460. return true;
  461. } catch (Exception e) {
  462. e.printStackTrace();
  463. return false;
  464. }
  465. }
  466. /**
  467. * 根据索引修改list中的某条数据
  468. * @param key 键
  469. * @param index 索引
  470. * @param value 值
  471. * @return
  472. */
  473. public boolean lUpdateIndex(String key, long index, Object value) {
  474. try {
  475. redisTemplate.opsForList().set(key, index, value);
  476. return true;
  477. } catch (Exception e) {
  478. e.printStackTrace();
  479. return false;
  480. }
  481. }
  482. /**
  483. * 移除N个值为value
  484. * @param key 键
  485. * @param count 移除多少个
  486. * @param value 值
  487. * @return 移除的个数
  488. */
  489. public long lRemove(String key, long count, Object value) {
  490. try {
  491. Long remove = redisTemplate.opsForList().remove(key, count, value);
  492. return remove;
  493. } catch (Exception e) {
  494. e.printStackTrace();
  495. return 0;
  496. }
  497. }
  498. }

五、登录实现(user-service)

UserDetails
  1. package com.pzhxy.user.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  3. import com.pzhxy.feign.domain.User;
  4. import com.pzhxy.security.domain.LoginUser;
  5. import com.pzhxy.user.mapper.PermissionMapper;
  6. import com.pzhxy.user.mapper.UserMapper;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.security.core.userdetails.UserDetails;
  9. import org.springframework.security.core.userdetails.UserDetailsService;
  10. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  11. import org.springframework.stereotype.Service;
  12. import java.util.List;
  13. import java.util.Objects;
  14. @Service("userDetailsService")
  15. public class UserDetalisServiceImpl implements UserDetailsService {
  16. /***
  17. * 进行认证,认证是从数据库查询账号密码
  18. *@Date:2022/5/22
  19. * @Author: Liu
  20. */
  21. @Autowired
  22. private UserMapper userMapper;
  23. @Autowired
  24. private PermissionMapper permissionMapper;
  25. @Override
  26. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  27. //调用usermapper,实现数据库查询
  28. QueryWrapper<User>wrapper=new QueryWrapper<>();
  29. wrapper.eq("id",username);
  30. User user = userMapper.selectOne(wrapper);
  31. if(Objects.isNull(user)){
  32. //数据库无该用户,认证失败
  33. throw new RuntimeException("用户名不存在");
  34. }
  35. //授权
  36. List<String> list = permissionMapper.selectPermsByUserId(user.getId());
  37. LoginUser loginUser=new LoginUser();
  38. loginUser.setUser(user);
  39. loginUser.setPermissions(list);
  40. return loginUser;
  41. }
  42. }
  1. package com.pzhxy.user.controller;
  2. import com.pzhxy.constant.result.ResultBean;
  3. import com.pzhxy.feign.domain.User;
  4. import com.pzhxy.user.service.impl.LoginServiceImpl;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.web.bind.annotation.*;
  7. @RestController
  8. @RequestMapping("/user")
  9. public class LoginController {
  10. @Autowired
  11. private LoginServiceImpl loginService;
  12. @PostMapping("/login")
  13. public ResultBean login(@RequestBody User user){
  14. return loginService.login(user);
  15. }
  16. @GetMapping("/logout")
  17. public ResultBean loginout(){
  18. return loginService.logout();
  19. }
  20. }

六、使用方式

在其他微服务中导入你的security服务的依赖即可

例如user-servcie

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/185349
推荐阅读
相关标签
  

闽ICP备14008679号