springboot实现简单的单点登录

思路

  1. 用户登录去校验用户信息,校验成功后将登录后的信息持久化,并返回一个系统可识别的信息串
  2. 用户每次访问接口将参数和信息串一起访问,然后通过拦截进行对信息串统一识别认证

实践

用户登录

通过用户名和密码验证是否登录成功,我这里是用accessToken作为系统可识别的信息串,持久化你可以存入数据库,也可以放在redis,但是经常要验证accessToken,建议放在redis中好一点。

 @ApiOperation("登录")
    @PostMapping("login")
    @AuthLogin(needLogin = false)
    public RestResponse<User> login(String username,String password){
        return RestResponse.ok(userService.login(username,password));
    }
@Override
   public UserVO login(String username, String password) {
   	User user = new User() ;
   	user.setUsername(username);
   	user.setPassword(password);
   	QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(user);
   	User users = this.getOne(userQueryWrapper);
   	if(users == null ){
   		throw new BusinessException("用户名或者密码错误");
   	}
   	//生成accessToken
   	String token = tokenService.createToken(users.getId());
   	users.setAccessToken(token);
   	//登录成功后返回用户信息和accessToken
   	return users.of();
   }

accessToken拦截和验证

accessToken拦截是通过拦截器进行拦截,其中包括哪些接口需要拦截,这里也会用到自定义注解,识别和使用,其次也会增加一些拦截器。
1.创建拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //全局登录拦截请求
        registry.addInterceptor(new AuthLoginIntercept()).addPathPatterns("/**")
                .excludePathPatterns("/file/**")
                .excludePathPatterns("/login/**")
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**")
                .excludePathPatterns("/druid/**");

    }

    /**
     * 上传文件外部访问拦截
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/file/**")
                .addResourceLocations("file:"+BaseUploadPath);
    }


}

2.自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Documented
@Inherited
public @interface AuthLogin {

    /**
     *是否需要登录
     * 默认:需要登录
     */
    boolean needLogin() default true ;

}

3.拦截器实现方法

@Service
public class AuthLoginIntercept extends HandlerInterceptorAdapter {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //拦截所有的请求方法,是否需要登录
            AuthLogin authLoginMethod = handlerMethod.getMethod().getAnnotation(AuthLogin.class);
            if(authLoginMethod != null && !authLoginMethod.needLogin()){
                return true;
            }
            //拦截整个模块,是否需要登录
            AuthLogin authLoginClass = handlerMethod.getBeanType().getAnnotation(AuthLogin.class);
            if(authLoginClass != null && !authLoginClass.needLogin()){
                return true;
            }
            //验证token信息
            this.validAuth();
        }
        return true;
    }


    /**
     * 验证token信息
     */
    private void validAuth(){
        String token = RequestUtil.getToken();
        TokenService tokenService = SpringUtil.getBean(TokenService.class);
        //验证token是否符合条件
        tokenService.validateToken(token);
    }
}

4.验证token

@Override
	public UserVO validateToken(String accessToken) {
		//通过解析token
		UserVO user = getUser(accessToken);
		//更新用户当前的最新信息
		User updateUser = new User();
		updateUser.setId(user.getId());
		updateUser.setLastLoginTime(new Date());
		userService.update(updateUser);
		return user;
	}

通过token获取用户信息

/**
	 * 获取用户信息
	 * @param accessToken
	 * @return
	 * @throws BusinessException
	 */
	public UserVO getUser(String accessToken)throws BusinessException {
		//验证token是否正确
		boolean validToken = validToken(accessToken);
		if(validToken){
		//解密token信息
			UserVO user = decodeUser(accessToken);
			validUser(user);
			return user;
		}
		return null;
	}

验证token的合法性

/**
	 * 校验token信息
	 * @param accessToken 认证
	 * @return
	 * @throws BusinessException
	 */
	public boolean validToken(String accessToken) throws BusinessException{
		if(StrUtil.isBlank(accessToken)){
			throw new BusinessException(Login.getCode(),NotLogin.getCode(),NotLogin.getMsg());
		}
		boolean keyExists = redisService.isKeyExists(AccessToken.getKey(), accessToken);
		if(!keyExists) {
			throw new BusinessException(Login.getCode(),TokenLose.getCode(), TokenLose.getMsg());
		}
		return true;

	}

我这里是用的base64加密用户信息

/**
	 * 解密用户信息
	 * @param accessToken
	 * @return
	 */
	public UserVO decodeUser(String accessToken){
		String userString= (String) redisService.get(AccessToken.getKey(), accessToken);
		String userJson = Base64.decodeStr(userString);
		return JSONObject.parseObject(userJson,UserVO.class);
	}

maven Jar包依赖

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
 <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
  <!-- 缓存依赖 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
          <scope>compile</scope>
      </dependency>
 <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>${fastjson.version}</version>
      </dependency>
  <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值