SpringCloud security +oauht2.0 授权码(authorization_code)模式+jwt 实现微服务的认证和授权(一)

1.授权码模式讲解

在这里插入图片描述
1.1:根据图片 我们看的出来 用户认证以后 我们拿到授权码 根据授权码 去获取token,那这个认证的过程 我们就不用去做了,我们只管用户登录成功以后 我们来拿到token

1.2:把password模式修改成 authorization_code 模式
password模式 如果你是看我这个文章来的 我们只需要 修改以下内容,如果你是新来了,可以去我的gitHub看这篇文章的源码 源码地址
1.3:修改 WebSecurityConfig 文件

package com.example.springcloudalibabaoauthauth.security;

import com.example.springcloudalibabaoauthauth.service.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * 2 * @Author: ZhangShuai
 * 3 * @Date: 2020/6/12 17:03
 * 4
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    //使用Security的认证管理器  认证操作security 给我们来做
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }


    //使用security的默认密码加密方式
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean  //主要是配置这个Bean,用于授权服务器配置中注入
    @Override
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }

    //配置security不拦截的请求  下面可以根据需求自定义 用,号隔开
    @Override
    public void configure(WebSecurity web) throws Exception {
        // 将 check_token 暴露出去,否则资源服务器访问时报 403 错误
        //配置暴露出去的端点  不用登陆就可以访问
        web.ignoring().antMatchers( "/GetToken", "/index.html", "/css/**", "/js/**",
                "/images/**",
                "/openid/login",
                "/oauth/check_token", "/queryToken");
    }

    //增加了这个方法
    @Override
    public void configure(HttpSecurity http) throws Exception {
        //禁止跨域请求
        http.csrf().disable()
                .formLogin()
                .loginPage("/index.html")  //不使用 security的登录页面 使用我们自己的登录页面
                .loginProcessingUrl("/loginSubmit")  //登录表单要提交的地址 这个地址不需要存在  保证表单提交的地址 和我们这里写的地址 是一样的
                .defaultSuccessUrl("/loginSuccess")  //登录 成功 要跳转的地址 这里 还有一个参数 是boolean类型的 默认为false
                .and()
                .authorizeRequests().anyRequest().authenticated();
    }
}

1.4:修改 JwtUser 实体类的内容

package com.example.springcloudalibabaoauthauth.util;

import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;
/**
 * Created by zhangshuai on 2020/6/22.
 */
@Data
public class JwtUser extends User {

    /**
     * 用户id
     */
    private Long id;

    /**
     * 用户名
     */
    private String username;

    /**
     *账号
     */
    private  boolean accountNonExpired;
    /**
     *账号是否被锁定
     */
    private  boolean accountNonLocked;
    /**
     * 帐号是否过期
     */
    private  boolean credentialsNonExpired;
    /**
     * 帐号是否被禁用
     */
    private  boolean enabled;

    /**
     * 构造方法
     * @param username
     * @param password
     * @param authorities
     * @param accountNonExpired
     * @param accountNonLocked
     * @param credentialsNonExpired
     * @param enabled
     */
    public JwtUser(String username, String password, Collection<? extends GrantedAuthority> authorities,  boolean accountNonExpired, boolean accountNonLocked, boolean credentialsNonExpired, boolean enabled) {
        super(username, password, authorities);
        this.accountNonExpired = accountNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.credentialsNonExpired = credentialsNonExpired;
        this.enabled = enabled;
    }


    /**
     * 让boolean的都变为true
     * @param username 用户名
     * @param password 密码
     * @param authorities  权限
     */
    public JwtUser(String username, String password,
                Collection<? extends GrantedAuthority> authorities) {
        this(username, password, authorities, true, true, true,true );
    }

}


1.5:修改 application.yml

server:
  port: 9090
spring:
  application:
    name: springcloud-oauth-auth
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.3.37/test?useUnicode=true&characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull
    password: zhangxiaoyun123
    username: root
  resources:
    static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/templates/
  thymeleaf:
    encoding: UTF-8
    suffix: .html
    cache: false
    # 配置前缀时必须加templates,浏览器访问页面时不加templates路径
    prefix: classpath:/templates/
#cloud:
#  nacos:
#    discovery:
#      #指定nacos server的地址
#      server-addr: 127.0.0.1:8848

logging:
  level:
    cloud.zxy.system: debug

2.增加 controller层

2.1 :AuthToken 定义返回令牌信息

package com.example.springcloudalibabaoauthauth.util;

import lombok.Data;

/**
 * Created by zhangshuai on 2020/6/22.
 */
@Data
public class AuthToken {
    /**
     * access_token
     */
    private String access_token;

    /**
     * 刷新令牌token
     */
    private String refresh_token;
    /**
     * jwt令牌
     */
    private String jwt_token;//jwt令牌

    /**
     * 令牌到期时间
     */
    private Integer expires_in;

    /**
     * 错误
     */
    private String error;

    /**
     * 申请令牌的错误信息
     */
    private String error_description;

}

2.2 LoginController:使用code获取令牌的一些逻辑

package com.example.springcloudalibabaoauthauth.controller;

import com.example.springcloudalibabaoauthauth.util.AuthToken;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * 2 * @Author: ZhangShuai
 * 3 * @Date: 2020/6/20 11:22
 * 4
 */
@RestController
@Slf4j
public class LoginController {

    @Autowired
    private RestTemplate restTemplate;

    /*登录的方法*/
    @GetMapping("loginSuccess")
    public String login(){
        return "ok";
    }

    /**
     * 前端 可以根据这个地址 拿到token
     * 获取code 的回调地址
     * @param code
     * @return
     */
    @GetMapping("GetToken")
    public AuthToken GetToken(@RequestParam String code){

        //这里可以让前端 给你传一个 值 拿到这个值 可以进行回调到 这个url
        log.info("code is " + code);
        String authUrl = "http://localhost:9090/oauth/token";
        //定义header
        LinkedMultiValueMap<String, String> header = new LinkedMultiValueMap<>();
        String httpBasic = getHttpBasic();
        header.add("Authorization", httpBasic);
        //定义body
        LinkedMultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type", "authorization_code");
        body.add("code", code);
        body.add("redirect_uri", "http://localhost:9090/GetToken");
        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(body, header);
        //调用登录认证服务 生成jwt令牌
        ResponseEntity<Map> exchange = restTemplate.exchange(authUrl, HttpMethod.POST, httpEntity, Map.class);
        //申请令牌信息
        AuthToken authToken = makeAuthToken(exchange);
        return authToken;
    }

    /**
     * 设置token值
     *
     * @param exchange 远程调用结果
     * @return
     */
    private AuthToken makeAuthToken(ResponseEntity<Map> exchange) {
        Map bodyMap = exchange.getBody();
        AuthToken authToken = new AuthToken();
        if (bodyMap == null ||
                bodyMap.get("access_token") == null ||
                bodyMap.get("refresh_token") == null ||
                bodyMap.get("jti") == null ||
                bodyMap.get("expires_in") == null
        ) {
            authToken.setError((String) bodyMap.get("error"));
            authToken.setError_description((String) bodyMap.get("error_description"));
            return authToken;
        }
        authToken.setAccess_token((String) bodyMap.get("access_token"));//用户身份令牌
        authToken.setRefresh_token((String) bodyMap.get("refresh_token"));//刷新令牌
        authToken.setJwt_token((String) bodyMap.get("jti"));//jwt令牌
        return authToken;
    }

    /*获取httpBasic的串*/
    private String getHttpBasic() {
        String string = "client" + ":" + "admin";
        //将串进行base64编码
        byte[] encode = Base64Utils.encode(string.getBytes());
        return "Basic " + new String(encode);
    }

}

2.3 resources:下面增加 static 和templates
在这里插入图片描述
下载链接:https://pan.baidu.com/s/1aG4APvMFluyDXu-YxD23zg
提取码:vdxj

3.测试授权码获取token

3.1:首先通过浏览器访问下面的地址获取授权码(code)

http://localhost:9090/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://localhost:9090/GetToken

注(这里的cilent 还有response_type 和 redirect_uri)必须在数据库配置 oauth_client_details
当我们访问上面地址的时候 会跳转到 首页让我们登录
在这里插入图片描述
3.2 登录成功 返回token
在这里插入图片描述
注意事项:
redirect_uri :必须保证和数据库的一致 不然会报这个错误
在这里插入图片描述
cilent :必须和数据库的一致
response_type=code:必须保证你配置了 授权码登录
源码地址

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

往日时光--

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值