springboot自定义注解+token验证+redis实现用户登录拦截

登录拦截有很多种方法,网上代码各式各样,我总结一下我最近用到的一种方法。

流程:用户登录后除了返回用户信息还会返给前端带有userId的一个token值,并将token值存入redis,前端拿着token去调用接口,在请求接口时拦截器会先检测该接口是否有自定义注解去做拦截验证,然后判断请求头中是否带有token请求及redis中token是否过期,然后进行拦截。
不多比比,直接上代码

1、创建自定义注解类

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.RetentionPolicy;
/**
 * 在不需要登录验证的Controller的方法上使用此注解
 */
@Target({ElementType.METHOD})// 可用在方法名上
@Retention(RetentionPolicy.RUNTIME)// 运行时有效
@Documented                             
@Inherited 
public @interface LoginRequired {
}

2、创建token工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;

public class TokenUtils {

	 /**
     * 签名秘钥
     */
    public static final String SECRET = "USER";

    /**
     * 生成token
     * @param id 一般传入userId
     * @return
     */
    public static String createJwtToken(String id){
        long ttlMillis = System.currentTimeMillis(); 
        return createJwtToken(id,ttlMillis);
    }
    
    /**
     * 生成Token
     * 
     * @param id
     *            编号
     * @param issuer
     *            该JWT的签发者,是否使用是可选的
     * @param subject
     *            该JWT所面向的用户,是否使用是可选的;
     * @param ttlMillis
     *            签发时间
     * @return token String
     */
    public static String createJwtToken(String id,long ttlMillis) {

        // 签名算法 ,将对token进行签名
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 生成签发时间
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        // 通过秘钥签名JWT
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECRET);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        // Let's set the JWT Claims	
        JwtBuilder builder = Jwts.builder().setId(id)
            .setIssuedAt(now)
            .signWith(signatureAlgorithm, signingKey);

        // if it has been specified, let's add the expiration
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }

        // Builds the JWT and serializes it to a compact, URL-safe string
        return builder.compact();

    }

    // Sample method to validate and read the JWT
    public static Claims parseJWT(String jwt) {
        // This line will throw an exception if it is not a signed JWS (as expected)
        Claims claims = Jwts.parser()
            .setSigningKey(DatatypeConverter.parseBase64Binary(SECRET))
            .parseClaimsJws(jwt).getBody();
        return claims;
    }
}

3、编写拦截器

import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.zewei.commons.redis.RedisUtil;

public class AuthenticationInterceptor implements HandlerInterceptor {

	//Redis根据自己业务代码调用
	@Autowired
	RedisUtil redisUtil;
	
	private static final Logger LOGGER= LoggerFactory.getLogger(AuthenticationInterceptor.class);
	
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(!(handler instanceof HandlerMethod)){
            LOGGER.info("没有映射到方法,则无需检查直接通过");
            return true;
        }
        HandlerMethod heHandlerMethod = (HandlerMethod)handler;
        Method method = heHandlerMethod.getMethod();
        //判断接口是否需要登录
        LoginRequired loginRequired=method.getAnnotation(LoginRequired.class);
        //有LoginRequired注解,不需要认证
        if(loginRequired!=null){
            return true;
        }
        //从header中获取token
        String token = request.getHeader("token");
        if (token!=null) {
        	//判断redis中token是否失效
			boolean falg = redisUtil.hasKey(token);
			if (falg) {
				return true;
			}
		}
        //登录状态检查,使用response返回给前端指定信息
        setHeader(request, response, "{\r\n" + 
        		"    \"code\": \"-1\",\r\n" + 
        		"    \"message\": \"请进行登录!\",\r\n" + 
        		"    \"data\": \"null\"\r\n" + 
        		"}");
        return false;
    }
    
    
    /**
     * response设置header,实现跨域
     * @param request
     * @param response
     * @param message	返回给前端的消息,json格式
     */
    @SuppressWarnings("unused")
	private void setHeader(HttpServletRequest request,HttpServletResponse response,String message){
    	 try {
	        //跨域的header设置
	        response.setHeader("Access-control-Allow-Origin", request.getHeader("Origin"));
	        response.setHeader("Access-Control-Allow-Methods", request.getMethod());
	        response.setHeader("Access-Control-Allow-Credentials", "true");
	        response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
	        //防止乱码,适用于传输JSON数据
	        response.setHeader("Content-Type","application/json;charset=UTF-8");
			response.getWriter().write(message);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

}

4、注入拦截器

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class WebConfig extends WebMvcConfigurationSupport {

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(authenticationInterceptor()).addPathPatterns("/**");

	}
	
	@Bean
	public AuthenticationInterceptor authenticationInterceptor() {
		return new AuthenticationInterceptor();
	}
}

5、控制层接口

	/**
	 * 用户登录
	 * 加@LoginRequired注解表示该接口不需要进行拦截
	 * @return
	 */
	@CrossOrigin
	@ResponseBody
	@LoginRequired
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	@ApiOperation(value = "用户登录")
	public ActionResponse<ModelMap> login(String account, String password, ModelMap model) {
		try {
			User user = userService.selectByUser(account,password);
			if (user != null) {
				//生成token
				String token = TokenUtils.createJwtToken(user.getuID());
				//将token存入redis,两小时失效
				redisUtil.set(token, token, 7200L);
				model.put("token", token);
				model.put("user", user);
				return new ActionResponse<ModelMap>(ErrorMsg.success.getCode(),
						ErrorMsg.success.getMessage(),model);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new ActionResponse<ModelMap>(ErrorMsg.error.getCode(), ErrorMsg.error.getMessage());
	}

如有不足或改进,欢迎大家指正,技术无界限,互相进步。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 好的,我会尽量详细地讲解使用 Spring Security 和 Redis 实现用户登录和权限控制的细节。 首先,你需要在你的项目中引入 Spring Security 和 Redis 的依赖。 在配置文件中,你需要配置 Redis 的连接信息,并且指定使用 Redis 作为 Spring Security 的缓存。 然后,你需要定义一个 UserDetailsService,它负责从数据库中读取用户的登录信息。在这个类中,你可以使用 RedisTemplate 将用户信息缓存到 Redis 中。 接着,你需要配置 Spring Security 的认证流程。这包括指定使用哪种认证方式(比如表单认证),以及如何处理登录请求和登录成功/失败的情况。 最后,你还需要配置权限控制。这包括指定哪些路径需要身份认证和授权,以及如何检查用户是否具有访问某个路径的权限。 在这些配置完成之后,当用户尝试访问受保护的路径时,Spring Security 会自动拦截请求并进行身份认证和权限检查。如果用户身份认证成功且具有访问该路径的权限,就会放行请求;否则, ### 回答2: 使用Spring Security和Redis实现用户登录以及权限控制主要涉及以下几个方面的细节: 1. 用户认证:用户输入用户名和密码后,Spring Security会将其传递给一个认证管理器(AuthenticationManager),该管理器会根据用户提供的信息进行认证。在认证过程中,可以使用Redis作为缓存存储用户信息,提高认证的效率。 2. 密码加密:为了增强安全性,用户的密码通常应该经过加密处理后才进行存储。Spring Security提供了多种加密方式,如BCrypt、SHA等,可以根据项目需求选择适合的加密方式。在存储用户密码时,可以使用Redis的存储功能进行持久化存储。 3. 授权管理:一旦用户通过认证,Spring Security会为该用户分配相应的权限。可以将用户的权限信息存储在Redis中,方便后续的权限控制操作。通过配置合适的访问规则,可以根据用户的角色或权限对不同的资源进行访问控制。 4. Session管理:在用户登录后,系统会为用户生成一个会话(Session),用于记录用户的登录状态。可以将会话信息存储在Redis中,由Spring Security进行管理。通过Redis的分布式存储特性,可以实现多个应用服务器之间的会话共享,增强系统的可扩展性和容错性。 使用Spring Security和Redis实现用户登录以及权限控制的细节可以通过使用Spring Security提供的相关注解和配置来完成。这些注解和配置包括用户认证的自定义逻辑、密码加密配置、权限配置、会话管理配置等。同时,为了实现Redis的集成,可以使用Spring Data Redis提供的工具类和注解,简化与Redis的交互操作。通过合理的配置和编码实现,可以保障系统的安全性和可扩展性。 ### 回答3: 使用Spring Security和Redis实现用户登录和权限控制的过程可以分为以下几个细节。 首先,我们需要在Spring Boot项目中配置Spring Security和Redis的相关依赖。在pom.xml文件中添加相应的依赖,并进行配置。 接下来,我们需要创建一个用户模型,包含字段如用户名、密码和权限等。可以使用Spring Data JPA来管理用户模型的持久化和CRUD操作。 在用户登录过程中,首先用户需要提供用户名和密码。Spring Security可以提供默认的登录表单页面,也可以自定义登录页面。用户提交登录请求后,Spring Security会拦截该请求,并通过验证用户名和密码的方式,验证用户身份的合法性。这可以通过自定义UserDetailsService来实现,UserDetailsService可以从数据库(MySQL等)中获取用户信息,用于验证用户身份。当验证成功后,Spring Security会生成一个Token,并将其存储到Redis中。 在权限控制方面,用户在登录后,可以通过访问需要权限的接口或资源。Spring Security可以通过对应的注解,如@PreAuthorize、@PostAuthorize等,在方法级别或类级别上添加权限控制规则。这些注解可以用来定义访问某个接口或资源需要的权限。当用户访问某个需要权限的接口时,Spring Security会通过TokenRedis中获取用户信息,并根据用户的权限与接口所需权限进行对比。如果用户拥有足够的权限,就可以访问接口;否则,将会返回403错误。 另外,在权限控制方面,可以利用Spring Security提供的@PreAuthorize注解进行动态权限控制,即根据用户当前的权限动态决定用户是否可以访问某个接口。这可以通过在注解中添加SpEL表达式来实现,例如:@PreAuthorize("hasAnyAuthority('admin','user')"),表示只有拥有admin或user权限的用户才能够访问该接口。 综上所述,使用Spring Security和Redis实现用户登录和权限控制,通过验证用户身份和对用户权限进行控制,可以保障系统的安全性和权限管理。该方案具备灵活性,并且可以与其他框架和工具(如Spring Cloud等)结合使用,实现更加完整的分布式系统的用户登录和权限控制功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值