用户登录,校验等

1.用户的登录

Spring Security Oauth2 认证(获取token/刷新token)流程(password模式)

1.项目中用户的登录:

1、客户端请求认证服务进行认证。
2、认证服务认证通过向浏览器cookie写入token(身份令牌)

  • 认证服务请求用户中心查询用户信息。
  • 认证服务请求Spring Security申请令牌。
  • 认证服务将token(身份令牌)和jwt令牌存储至redis中。
  • 认证服务向cookie写入 token(身份令牌)

2.用户在前端的显示:

前端携带身份(token)请求认证服务获取jredis中存储的wt令牌

  • 前端获取到jwt令牌并存储在sessionStorage。
  • 前端从jwt令牌中解析中用户信息并显示在页面

3.用户的退出

  • 删除redis中的token
  • 删除cookie中的token。

1.1.首先申请到令牌

申请令牌的URL固定为:/oauth/token。这里使用了ResponseEntity<Map> exchange = restTemplate.exchange(authUrl, HttpMethod.POST, httpEntity, Map.class);这种远程调用eureka中自己的服务,申请到令牌。
申请获取令牌,首先需要在自定义的UserDetailsService的实现类loadUserByUsername()方法中校验的是Basic Auth 中的Client_id,Client_security。通过之后然后在相同的类,方法中校验用户名和密码。两个都通过之后,才会生成令牌。具体的步骤在上篇文章中有介绍。

1.2将令牌存储到redis,其中身份令牌存储到Cookie中。

这个是总的代码。

    public AuthToken login(String username, String password, String clientId, String clientSecret) {
        //1.首先申请到令牌
        AuthToken authToken = applyToken(username, password, clientId, clientSecret);
        if(authToken==null){
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
        }
        //用户身份令牌
        String access_token = authToken.getAccess_token();

        String jsonString = JSON.toJSONString(authToken);
        //将令牌存储到redis
        boolean result = this.saveToken(access_token, jsonString, tokenValiditySeconds);
        if (!result) {
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL);
        }
        return authToken;
    }

1.1.首先申请到令牌

//申请令牌
    private AuthToken applyToken(String username, String password, String clientId, String clientSecret) {
        //从eureka中获取认证服务的地址(因为spring security在认证服务中)
        //从eureka中获取认证服务的一个实例。
        ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);
        //此地址就是http://ip:port
        URI uri = serviceInstance.getUri();
        //令牌申请的地址 http://localhost:40400/auth/oauth/token
        String authUrl = uri+ "/auth/oauth/token";
        //定义header
        LinkedMultiValueMap<String, String> header = new LinkedMultiValueMap<>();

        String httpBasic = getHttpBasic("clientId", "clientSecret");
        header.add("Authorization",httpBasic);

        //定义body
        LinkedMultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type","password");
        body.add("username",username);
        body.add("password",password);

        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(body, header);
        //String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables

        //设置restTemplate远程调用时候,对400和401不让报错,正确返回数据
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                if(response.getRawStatusCode()!=400 && response.getRawStatusCode()!=401){
                    super.handleError(response);
                }
            }
        });

        ResponseEntity<Map> exchange = restTemplate.exchange(authUrl, HttpMethod.POST, httpEntity, Map.class);

        //申请令牌消息
        Map bodyMap = exchange.getBody();

        if (bodyMap == null ||
                bodyMap.get("access_token") == null ||
                bodyMap.get("refresh_token") == null ||
                bodyMap.get("jti") == null) {

            System.out.println(bodyMap.get("error_description"));
            //解析spring security返回的错误信息
            if (bodyMap != null && bodyMap.get("error_description") != null) {
                String error_description = (String) bodyMap.get("error_description");
                if (error_description.indexOf("UserDetailsService returned null") >= 0) {
                    ExceptionCast.cast(AuthCode.AUTH_ACCOUNT_NOTEXISTS);
                } else if (error_description.indexOf("坏的凭证") >= 0) {
                    ExceptionCast.cast(AuthCode.AUTH_CREDENTIAL_ERROR);
                }
            }
            return null;
        }

        AuthToken authToken = new AuthToken();
        authToken.setAccess_token((String) bodyMap.get("jti"));//用户身份令牌
        authToken.setRefresh_token((String) bodyMap.get("refresh_token"));//刷新令牌
        authToken.setJwt_token((String) bodyMap.get("access_token"));//jwt令牌
        return authToken;
    }

    private String getHttpBasic(String clientId,String clientSecret){
        String string = clientId+":"+clientSecret;
        byte[] encode = Base64Utils.encode(string.getBytes());
        return "Basic"+new String(encode);
    }
    public AuthToken getUserToken(String token){
        String key ="user_token:"+token;
        String value = stringRedisTemplate.opsForValue().get(key);
        //转成对象
        try {
            AuthToken authToken = JSON.parseObject(value, AuthToken.class);
            return authToken;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }


    }
}

1.2将令牌存储到redis

 private boolean saveToken(String access_token,String content,long ttl){
        String key = "user_token:"+access_token;
        stringRedisTemplate.boundValueOps(access_token).set(content,ttl, TimeUnit.SECONDS);
        Long expire = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
        return expire>0;
    }

将令牌存储到Cookie中.

  //将令牌存储到cookie
    private void saveCookie(String token){
        //RequestContextHolder顾名思义,持有上下文的Request容器
         HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
    如果是删除Cookie中的内容的话,只需要把cookieMaxAge修改为0,即可。 
      CookieUtil.addCookie(response,cookieDomain,"/","uid",token,cookieMaxAge,false);
    }

用户的授权

springcecuriy中本身提供的User对象中就含有authrities属性,我们通过继承它实现自己的类。然后赋予相应的权限。
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值