springcloud + oauth2

http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

1、什么是OAuth
OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用。目前的版本是2.0版。
OAuth的作用就是让"客户端"安全可控地获取"用户"的授权,与"服务商提供商"进行互动
在这里插入图片描述
OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(authorization layer)。“客户端"不能直接登录"服务提供商”,只能登录授权层,以此将用户与客户端区分开来。"客户端"登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。
"客户端"登录授权层以后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料。
2、OAuth2的四种模式:
a、授权码模式(别人来调用我们的服务)
b、简化模式(pc模式,跳过了"授权码"这个步骤)
c、密码模式(自己的服务)
d、客户端模式(服务与服务之间的调用)

一、springcloud + OAuth2
1方案:
在这里插入图片描述
添加pom依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

认证服务配置:

import com.gao.handler.MyAuthorationFaileHandler;
import com.gao.handler.MyAuthorationSeccuserHandler;
import com.gao.handler.MyAuthorictionDeniedHandler;
import com.gao.service.MyUserDetailService;
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.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

@Configuration
@EnableWebSecurity
@EnableGlobalAuthentication //开启全局的注解授权(使用注解授权)
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

	/**
	*  配置认证管理器,授权模式为“poassword”时会用到
	*/
    @Override
    @Bean 
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Bean
    public PersistentTokenRepository getTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        //第一次启动的时候创建表
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

    //加密配置
    @Bean
    public PasswordEncoder getPwdEncoder(){
         return new BCryptPasswordEncoder();
    } 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //查询所有的权限
        http.exceptionHandling().accessDeniedHandler((new MyAuthorictionDeniedHandler()))//没有权限时返回的信息           .and().authorizeRequests().antMatchers("/login").permitAll()//匹配所有,对登录请求全部放行
//                .antMatchers("/login.html").permitAll()//自定义登录页面放行
                .anyRequest().authenticated()//比对请求,进行权限验证
                .and().formLogin()//允许表单登录
//                .successForwardUrl("/succeed")//登录成功后的跳转请路径
                .successHandler(new MyAuthorationSeccuserHandler())
                .failureHandler(new MyAuthorationFaileHandler())
//                .loginPage("/login.html")//登录页面
//                .loginProcessingUrl("/login")
                .and().logout().permitAll()//允许所有的退出操作
                .and().csrf().disable();  //关闭跨站请求

        //记住我设置
        http.rememberMe()
                .tokenRepository(getTokenRepository())
                .userDetailsService(new MyUserDetailService())
                .tokenValiditySeconds(3600);
    } 
}
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class MyUserDetailService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //根据传入的用户名去数据库查询用户
        //判断是否为空,
            //空,抛出异常
            //非空,返回用户

        List<GrantedAuthority> authorities = new ArrayList<>();
        //查询权限
        List<Object> userPremis = new ArrayList<>();
        userPremis.forEach(t->{
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("权限值");
            authorities.add(simpleGrantedAuthority);
        });
//        public User(String username, String password, Collection<? extends GrantedAuthority > authorities) {
//            this(username, password, true, true, true, true, authorities);
//        }
        return new User("username","password",authorities);
    }
}

授权服务配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

import javax.annotation.Resource;
import javax.sql.DataSource;
 
@Configuration

@EnableAuthorizationServer //开启授权服务配置,声明该服务作为授权服务方
public class MyAuthSecurityConfig extends AuthorizationServerConfigurerAdapter {
	//授权服务安全配置:配置哪些路径放行(检查token的路径要放行)
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("permitAll()")   //对应/oauth/check_token ,路径公开
                .allowFormAuthenticationForClients(); //允许客户端进行表单身份验证,使用表单认证申请令牌
    }
    
 	@Resource
    private DataSource dataSource;
    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

	/*客户端详情:配置客户端请求的参数
	ClientDetailsServiceConfigurer 是这对于客户端详情的配置,我们通过withClientDetails关联一个JdbcClientDetailsService,默认会去找数据库中的名字为 oauth_client_details 表中的数据作为客户端详情的配置*/
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
       clients.withClientDetails(getDetailsService());
    } 
    public ClientDetailsService getDetailsService(){
        JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource); jdbcClientDetailsService.setPasswordEncoder(bCryptPasswordEncoder);
        return jdbcClientDetailsService;
    }

    @Resource
    private AuthenticationManager authenticationManager;

	//授权服务端点:配置授权码和令牌的管理/存储方式
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.authorizationCodeServices(getCodeServices()); //授权码的管理服务 ,默认读取 oauth_code表
        endpoints.tokenServices(getTokenServices()); //令牌的管理服务
        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);
    }

    @Bean
    public AuthorizationServerTokenServices getTokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(getDetailsService()); //指定客户端详情配置
        services.setSupportRefreshToken(true);  //支持产生刷新token
        services.setTokenStore(declareTokenStore()); //token存储方式
        return services;
    }

	//基于内存的Token存储
    public TokenStore declareTokenStore() {
        return new InMemoryTokenStore();
    }

    @Bean
    public AuthorizationCodeServices getCodeServices() {
        return new JdbcAuthorizationCodeServices(dataSource);
    }
}

1、ClientDetailsServiceConfigurer :用来配置客户端详情服务:如配置客户端id(client_id)资源id、客户端密钥(secrect)、授权方式、scope等,可以基于内存或jdbc。(可以理解为是对浏览器向授权服务器获取授权码或令牌时需要提交的参数配置)
2、AuthorizationServerEndpointsConfigurer:配置令牌的访问端点url和令牌服务,如配置如何管理授权码(内存或jdbc),如何管理令牌(存储方式,有效时间等等)
3、AuthorizationServerSecurityConfigurer: 用来配置令牌端点的安全约束,如配置对获取授权码,检查token等某些路径进行放行

创建客户端详情配置表SQL

DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
  `client_id` varchar(48) NOT NULL,
  `resource_ids` varchar(256) DEFAULT NULL,
  `client_secret` varchar(256) DEFAULT NULL,
  `scope` varchar(256) DEFAULT NULL,
  `authorized_grant_types` varchar(256) DEFAULT NULL,
  `web_server_redirect_uri` varchar(256) DEFAULT NULL,
  `authorities` varchar(256) DEFAULT NULL,
  `access_token_validity` int(11) DEFAULT NULL,
  `refresh_token_validity` int(11) DEFAULT NULL,
  `additional_information` varchar(4096) DEFAULT NULL,
  `autoapprove` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`

创建授权码SQL

DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
`code` varchar(255) DEFAULT NULL COMMENT '授权码(未加密)',
`authentication` varbinary(5000) DEFAULT NULL COMMENT 'AuthorizationRequestHolder.java对象序列化后的二进制数据'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

授权测试:
第一步,通过浏览器获取授权码,GET访问:

http://localhost:8100/oauth/authorize?client_id=webapp2&response_type=code&redirect_uri=http://www.baidu.com

第二步,使用Postmain获取令牌,Post访问

http://localhost:8100/oauth/token?client_id=webapp2&client_secret=123&grant_type=authorization_code&code=gD8ZbB&redirect_uri=http://www.baidu.com

刷新token:

http://localhost:8100/oauth/token?grant_type=refresh_token&refresh_token=刷新Token值&client_id=webapp&client_secret=secret

资源方配置

在资源服务中我们需要解决的问题是,当请求进来,请求是需要携带token,我们需要配置资源服务如何对token进行校验和授权

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;

@Configuration
@EnableResourceServer //作为资源服务方
public class MyRresourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("courseId");
        resources.tokenServices(getResourceTokenServices());
    }

    @Bean
    public ResourceServerTokenServices getResourceTokenServices() {
        //使用远程服务请求授权服务器校验token , 即:资源服务和授权服务器不在一个主机
        RemoteTokenServices services = new RemoteTokenServices();
        //授权服务地址 , 当浏览器访问某个资源时就会调用该远程授权服务地址去校验token
        //要求请求中必须携带token
        services.setCheckTokenEndpointUrl("http://localhost:8100/oauth/check_token");
        //客户端id,对应认证服务的客户端详情配置的clientId
        services.setClientId("webapp");
        //密钥,对应认证服务的客户端详情配置的clientId
        services.setClientSecret("123");
        return services;
    }

    /**
     * http安全配置
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //校验scope必须为all , 对应认证服务的客户端详情配置的clientId
                .antMatchers("/**").access("#oauth2.hasScope('all')")
                //关闭跨域伪造检查
                .and().csrf().disable()
                //把session设置为无状态,意思是使用了token,那么session不再做数据的记录
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

单点登录:
sso single sign on
在一个站点登录,其他站点在一定时间内都不用重现登录

共享token
Cookie:
cookie可以跨站。cookie不可跨域调用。每次请求一个新的页面的时候cookie都会被发送过去
sessionstorage
sessionStorage是在同源的窗口中,始终存在数据。也就是说,这个浏览器没有关闭,即使刷新页面或进入到同源另一个页面,数据仍然存在,关闭后,sessionstorage就会被销毁。
localstorage

无感刷新:
如果用户还在操作,此时token过期了,应该系统自动获取新token
1、如果token过期了,访问后台报错,报错了如果是过期的异常,全局异常中捕获该异常,捕获以后重新获取新的token 返回给前端。
2、在过期时间还有5分钟的时候,前端主动发送一个请求
3.1、在离过期时间还有5分钟之内自动刷新token
3.2、最后一次操作在过期时间之后,但是离上一次操作的时间差值在30分钟之内

outTime :过期时间
curTime :当前时间
lastTime : 最后一次操作时间
过期前5分钟内自动刷新
if(outTime - curTime < 5 && outTime - curTime > 0){
//刷新token
}

$.cookie("lastTime",lastTime)

if(lastTime > outTime  && cutTime > expTime  && curTime - lastTime <=30){
//刷新token
}
$.token('lastTime',curTime)


【注意】当配置域名之后,在访问页面的时候使用域名进行访问。避免无法使用cookie

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SpringCloud是一款开源的微服务框架,OAuth2是一种授权框架,Vue是一个流行的前端框架,ElementUI是一套基于Vue开发的UI框架。结合这些技术栈进行前后端分离的快速上手项目实战开发,可以提高开发效率和代码的可维护性。 实践中,可以按照以下步骤进行快速上手项目开发: 1. 搭建后端服务:使用SpringCloud搭建微服务架构,并引入Spring Security和OAuth2来实现认证和授权功能,确保后端接口的安全性。 2. 配置OAuth2服务端:在后端服务中配置OAuth2的服务端,定义认证服务器和资源服务器,配置客户端信息,如客户端ID、客户端密钥等。 3. 开发前端界面:使用Vue构建前端界面,并引入ElementUI来快速搭建页面和组件。利用Vue的组件化开发方式,可以更高效地开发各种交互功能。 4. 实现登录认证:在前端界面中使用OAuth2的授权码模式来实现用户登录认证功能,通过向认证服务器发送请求来获取访问令牌,并将令牌保存到前端的Cookie或localStorage中。 5. 发起请求并解析响应:在前端界面中使用Axios库来发起HTTP请求,并在请求头中携带访问令牌,后端服务器根据令牌进行权限验证。前端收到响应后解析数据,并进行相应的操作。 6. 实现权限控制:根据后端接口的权限设定,在前端界面中进行权限控制,隐藏或禁用没有权限的功能。可以通过在请求头中携带用户的角色信息,与后端进行验证。 7. 编写测试用例:保证代码的质量和功能的稳定性,编写相应的测试用例来进行单元测试和接口测试,确保项目的正确运行。 通过以上步骤,可以快速上手并实战开发SpringCloudOAuth2、Vue和ElementUI结合的前后端分离项目。不仅可以提高开发效率,还能保证项目的安全性和可维护性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值