使用Oauth2认证登录

使用的Oayth2的密码模式自定义认证服务来进行认证,同时使用了JWT令牌,RAS非对称加密算法,加上Spring Securuty 安全认证框架

流程:
在这里插入图片描述

认证服务controller层认证操作:

@RestController
@RequestMapping("/oauth")
public class AuthController {

    @Autowired
    private AuthService authService;

    @Value("${auth.clientId}")
    private String clientId;//客户端id

    @Value("${auth.clientSecret}")
    private String clientSecret;//客户端密码

    //可以访问该Cookie的域名。例如,如果设置为.zhihu.com,则所有以zhihu.com,结尾的域名都可以访问该Cookie。
    @Value("${auth.cookieDomain}")
    private String cookieDomain;

    //COOKIE的最大生命周期,-1为无生命周期,即只在当前打开的窗口有效,关闭或重新打开其它窗口,仍会要求验证
    @Value("${auth.cookieMaxAge}")
    private String cookieMaxAge;

    //如果设置为/,则本域名下的所有页面都可以访问该Cookie。
    @Value("${auth.cookiePath}")
    private String cookiePath;


    @PostMapping("/login")
    public Result login(String username, String password, HttpServletResponse response){
        //封装
        Map<String,String> map = new HashMap<>();
        map.put("clientId",clientId);
        map.put("clientSecret",clientSecret);
        map.put("username",username);
        map.put("password",password);
        //调用业务层获取jwt令牌
        AuthToken jwt = authService.getJwt(map);
        //向responsse中添加Cookie,参数1请求对象,参数2域名,参数3cookie的名称
        // 参数4cookie的值,参数5cookie的声明周期,参数6如果为true就不可以通过getCookie来获取cookie
        CookieUtil.addCookie(response,cookieDomain,cookiePath,"jti",jwt.getJti(),Integer.parseInt(cookieMaxAge),false);

        return new Result(true, StatusCode.OK,"登录成功");
    }
}

中间使用了cookieUtil工具类,本博客中有,自行去找;
server层业务操作

@Service
public class AuthServiceImpl implements AuthService {

    //发送获取jwt令牌请求的对象
    @Autowired
    private  RestTemplate restTemplate;

    //操作rdis数据库的对象
    @Autowired
    private RedisTemplate redisTemplate;

    //获取配置文件中设置的jwt在redis的过期时间
    @Value("${auth.ttl}")
    private long ttl;


    //获取jwt令牌
    @Override
    public AuthToken getJwt(Map<String, String> map) {
        if (map==null){
            throw  new RuntimeException("参数为空");
        }
        String clientId = map.get("clientId");//客户端id
        String clientSecret = map.get("clientSecret");//客户端密码
        if (StringUtils.isEmpty(clientId)||StringUtils.isEmpty(clientSecret)){
            throw new RuntimeException("客户端id或客户端密码有误");
        }
        //封装请求头
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        //请求头的键是Authorization  值是Basic clientId:clientSecret的Base64编码
        StringBuilder value = new StringBuilder(clientId+':'+clientSecret);
        headers.add("Authorization","Basic "+ Base64Utils.encodeToString(value.toString().getBytes()));

        //创建url,http://服务名,restTemplate会根据这个名称去eureka中去找路径
        //在配置restTemplate是就加了开启负载均衡的注解,因为可能认证服务是以集群的方式部署的
        String url ="http://user-auth/oauth/token";
        //封装请求体
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type","password");
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            if (!"clientId".equals(entry.getKey())&&!"clientSecret".equals(entry.getKey())){
                body.add(entry.getKey(),entry.getValue());
            }
        }

        //封装请求携带的键值对参数
        HttpEntity requestEntity = new HttpEntity(body,headers);
        //发送请求,参数1url,参数2请求方式,参数3 封装了请求头和请求体的内容,参数4要求响应回来的数据类型
        ResponseEntity<Map> mapResponseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);

        //获取jwt令牌
        Map jwtMap = mapResponseEntity.getBody();
       if (jwtMap==null){
           throw new  RuntimeException("令牌获取失败");
       }
        String access_token = (String) jwtMap.get("access_token");//获取jwt令牌
        String jti = (String) jwtMap.get("jti");//获取jti短令牌
        String refresh_token = (String) jwtMap.get("refresh_token");//获取刷新令牌
        //如果获取的都是空的代表令牌获取失败
        if (StringUtils.isEmpty(access_token)||StringUtils.isEmpty(jti)||StringUtils.isEmpty(refresh_token)){
            throw new RuntimeException("令牌获取失败");
        }
        //将jwt存入redis,jti是键,jwt令牌是值,ttl是过期时间,timeunit.seconds是时间单位秒
        redisTemplate.boundValueOps(jti).set(access_token,ttl, TimeUnit.SECONDS);

        //封装,然后返回
        AuthToken authToken = new AuthToken();
        authToken.setAccessToken(access_token);
        authToken.setJti(jti);
        authToken.setRefreshToken(refresh_token);
        return authToken;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值