如何设计一套单点登录系统(下)

3.2、token存放客户端

还有一种方案,是将token存放客户端,这种方案就是服务端根据规则对数据进行加密生成一个签名串&#nosql数据库是什么的缩写xff0c;这个签名串就是我们所说的token,最后返回给前端。

因为加密的操作都是在服务端完成的,因此密钥的阿飘是什么意思管理非常重要,不能泄露rediscover出去,不然很容易被黑客解密出来存储容量单位

最典型的应用就是JW缓存清理T!nosql怎么读;

JWT安全 是由三段信息构成的apicf0c;将这三段信息文本用.链接一起就构成了JWT字符串。就像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

如何实现呢?首先我们需要添加一个jwt依赖包。

<!-- jwt支持 -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

然后,创建一个用户信息类,将会通过加密存放在token

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class UserToken implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 用户ID
     */
    private String userId;
    /**
     * 用户登录账户
     */
    private String userNo;
    /**
     * 用户中文名
     */
    private String userName;
}

接着nosql与mysql的区别,创建一个JwtTokenUtil工具类,用于创建token、验证token

public class JwtTokenUtil {
 //定义token返回头部
    public static final String AUTH_HEADER_KEY = "Authorization";
 //token前缀
    public static final String TOKEN_PREFIX = "Bearer ";
 //签名密钥
    public static final String KEY = "q3t6w9z$C&F)J@NcQfTjWnZr4u7x";
 //有效期默认为 2hour
    public static final Long EXPIRATION_TIME = 1000L*60*60*2;
    /**
     * 创建TOKEN
     * @param content
     * @return
     */
    public static String createToken(String content){
        return TOKEN_PREFIX + JWT.create()
                .withSubject(content)
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .sign(Algorithm.HMAC512(KEY));
    }
    /**
     * 验证token
     * @param token
     */
    public static String verifyToken(String token) throws Exception {
        try {
            return JWT.require(Algorithm.HMAC512(KEY))
                    .build()
                    .verify(token.replace(TOKEN_PREFIX, ""))
                    .getSubject();
        } catch (TokenExpiredException e){
            throw new Exception("token已失效,请重新登录",e);
        } catch (JWTVerificationException e) {
            throw new Exception("token验证失败!",e);
        }
    }
}

同时编写配置类,允许跨域,并且创NOSQL建一个权限拦截前端开发前景怎么样啊

@Slf4j
@Configuration
public class GlobalWebMvcConfig implements WebMvcConfigurer {
    /**
     * 重写父类提供的跨域请求处理的接口
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 添加映射路径
        registry.addMapping("/**")
                // 放行哪些原始域
                .allowedOrigins("*")
                // 是否发送Cookie信息
                .allowCredentials(true)
                // 放行哪些原始域(请求方式)
                .allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS", "HEAD")
                // 放行哪些原始域(头部信息)
                .allowedHeaders("*")
                // 暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                .exposedHeaders("Server","Content-Length", "Authorization", "Access-Token", "Access-Control-Allow-Origin","Access-Control-Allow-Credentials");
    }
    /**
     * 添加拦截     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加权限拦截        registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**");
    }
}

使用AuthenticationInterceptor拦截缓存视频怎样转入相册器对接口参数进行验证

@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从http请求头中取出token
        final String token = request.getHeader(JwtTokenUtil.AUTH_HEADER_KEY);
        //如果不是映射到方法,直接通过
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        //如果是方法探测,直接通过
        if (HttpMethod.OPTIONS.equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }
        //如果方法有JwtIgnore注解,直接通过
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method=handlerMethod.getMethod();
        if (method.isAnnotationPresent(JwtIgnore.class)) {
            JwtIgnore jwtIgnore = method.getAnnotation(JwtIgnore.class);
            if(jwtIgnore.value()){
                return true;
            }
        }
        LocalAssert.isStringEmpty(token, "token为空,鉴权失败!");
        //验证,并获取token内部信息
        String userToken = JwtTokenUtil.verifyToken(token);
        //将token放入本地缓存
        WebContextUtil.setUserToken(userToken);
        return true;
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //方法结束后,移除缓存的token
        WebContextUtil.removeUserToken();
    }
}

最后&#xjavaeeff0c;在controller层用户登录之后,创建一个token,存放在头部即可

/**
 * 登录
 * @param userDto
 * @return
 */
@JwtIgnore
@RequestMapping(value = "/login", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
public UserVo login(@RequestBody UserDto userDto, HttpServletResponse response){
    //...参数合法性验证
    //从数据库获取用户信息
    User dbUser = userService.selectByUserNo(userDto.getUserNo);
    //....用户、密码验证
    //创建token,并将token放在响应头
    UserToken userToken = new UserToken();
    BeanUtils.copyProperties(dbUser,userToken);
    String token = JwtTokenUtil.createToken(JSONObject.toJSONString(userToken));
    response.setHeader(JwtTokenUtil.AUTH_HEADER_KEY, token);
    //定义返回结果
    UserVo result = new UserVo();
    BeanUtils.copyProperties(dbUser,result);
    return result;
}

到这里基javaee本就完成了!

其中Authenticajava怎么读tionInterceptor中用到的JwtIgnore是一个注解,用于不需要验证token的方法上,例如验证码的获取等等。

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JwtIgnore {
    boolean value() default true;
}

WebContextUtil是一个线程缓存工具类,其他接口通过这存储处理国家秘密的计算机信息个方法即可从token中获取用户信息。

public class WebContextUtil {
    //本地线程缓存token
    private static ThreadLocal<String> local = new ThreadLocal<>();
    /**
     * 设置token信息
     * @param content
     */
    public static void setUserToken(String content){
        removeUserToken();
        local.set(content);
    }
    /**
     * 获取token信息
     * @return
     */
    public static UserToken getUserToken(){
        if(local.get() != null){
            UserToken userToken = JSONObject.parseObject(local.get() , UserToken.class);
            return userToken;
        }
        return null;
    }
    /**
     * 移除token信息
     * @return
     */
    public static void removeUserToken(){
        if(local.get() != null){
            local.remove();
        }
    }
}

对应用系统而言,重点在于java模拟器token的验证,可以将拦截器方法封装成一个公共的jar包,然后各个应用系统引用即可!

和上面阿飘介绍的token存储到redis方案类似前端开发java培训f0c;不同点在于:一个将用户数据存储到redis阿飘是什么意思ÿnosql数据库的特点0c;另一个是采用加密算法存储到客户端进行传输。

四、小结java

在实际的使用过程中ÿjava语言0c;我个人更加倾向于采用jwt方案,直接在服务端使用签名加密算法API生成一个tokenÿnosql全称0c;然后在客户端进行流转,天然支持分布式,但是要注意加密时用的密钥要安全管理。

而采用redis方案存储的时候,你需要搭建高可用的集群环境,同时保证缓存数据不会失效等等,维护成本高!

在实际的实现上,每个公司玩法不一java样,有的安全性要求高,后端还会加上密钥环节进行安全验证,基本思缓存视频怎样转入本地视频路大同小异。