spring cloud oauth2.0 鉴权

本贴最后更新于 1807 天前,其中的信息可能已经事过景迁

spring cloud oauth2.0 鉴权

标签(空格分隔): springcloud oauth 鉴权


[TOC]

1.概述

文章主要是描述 springcloud 的一个鉴权,利用 oauth2.0 和 security 实现,所以也继承了 security 的权限框架,粒度可以达到按钮级别,具体还是要看设计思路

这里会介绍 3 种的 token 存储方式,(基于内存,基于 redis,基于 jwt)

还有两种 client 的配置方式,一种是采用官方数据库进行初始化,另一种是写在代码内存中。

2.实现流程

在这简单的说一下,不说的那么复杂。一个注册中心,一个鉴权的服务(我暂时把用户也放在鉴权服务里了,你若是喜欢也可以单独分出去),一个 A 服务(就几个简单的 controller 接口)。

项目启动后,用户通过/oauth/token 获取到 access_token,然后通过 access_token 可以请求具体接口,在资源服务器(也就是 A 服务)的配置文件中可以加入一个获取用户信息的配置项,这样就可以把用户信息获取得到,进行权限的判断。

暂时没有用网关去做 oauth2.0 的统一验证,我觉得网关还是只做转发路由,具体还是看情况吧。

3.代码实现

3.1 注册中心 eureka

这个没什么好说的,我用的是 springboot2.0.4 版本,cloud 版本为 Finchley.RELEASE

server:
  port : 8761
eureka:
  instance:
    hostname : localhost
  client:
    registerWithEureka : false
    fetchRegistry : false
    serviceUrl:
      defaultZone : http://${eureka.instance.hostname}:${server.port}/eureka/

3.2 资源服务器

配置文件

spring:
  application:
    name: oauth-a
  mvc:
    servlet:
      load-on-startup: 1   #初始化加载,不用懒加载
server:
  port: 8888
eureka:
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:8761/eureka/
    registry-fetch-interval-seconds: 5
  instance:
    lease-expiration-duration-in-seconds: 15
    lease-renewal-interval-in-seconds: 5
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${server.port}
logging:
  level:
    root: info
security:
  oauth2:
    resource:
      user-info-uri: http://127.0.0.1:7777/user/user-me
      prefer-token-info: false

主要是看后面一段 security 配置

配置了一个资源访问的地址,通过这个接口可以获取到登录的用户信息,而这个用户里面的信息包含的内容,要看你在登录的时候设置了什么了,具体看下面的鉴权的服务,一般会在里面返回所有角色信息和权限信息,在security的权限框架中,没有把角色和权限分开,都是统一用的一个集合,所以在角色里要默认加一个ROLE的前缀,如(ROLE_ADMIN,ROLE_USER)

security.oauth2.resource.user-info-uri:配置userinfo的url地址
security.oauth2.resource.token-info-uri:配置check-token的url地址;
security.oauth2.resource.prefer-token-info=true,如果上面两个都配置了,更倾向于用哪个

然后我们看一下主要的资源服务器配置:
ResourceServerConfig.java

package com.example.oautha.config;

import java.util.HashMap;

import javax.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
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.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 资源服务配置
 *
 */
@EnableResourceServer
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @SuppressWarnings({ "unchecked", "rawtypes", "serial" })
	@Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().exceptionHandling()
                .authenticationEntryPoint((req, resp, exception) -> {
                    resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                    resp.getWriter().write(new ObjectMapper().writeValueAsString(new HashMap() {{
                        put("status", 0);
                        put("error", "没有权限");
                    }}));
                })
                .and().authorizeRequests()
                .antMatchers("/anon/**").permitAll() // 放开权限的url
                .anyRequest().authenticated().and().httpBasic();

        http.headers().frameOptions().sameOrigin();
    }

}

中间有一个自定义的返回信息设置,看大家喜好,也可以不要。

然后是上面有一个注解 @EnableGlobalMethodSecurity(prePostEnabled = true),开启这个注解为 true,才可以使用 security 的权限控制。如下面的 controller

TestController.java

3.3 授权服务器

首先看用户登录这一块:

@Service("userDetailsServiceImpl")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userDao.findByUsername(username);
        if (user == null) {
            throw new AuthenticationCredentialsNotFoundException("用户不存在");
        } 
        return user;
    }

}

这是重写了框架自带的一个加载方法,密码校验框架底层做了判断,哦我们只要把信息输入进去就行,而角色和权限信息在此时也需要设置进去,在这里的 User 类是实现了 UserDetails 接口的,如:

@Data
public class User implements UserDetails{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Long id;
	private String username;
	private String password;
	
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		//默认给一个用户角色,生产环境自己添加相应的角色和权限
		return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
	}
	@Override
	public boolean isAccountNonExpired() {
		//判断用户是否过期,默认为true,生产环境视情况修改,赋值
		return true;
	}
	@Override
	public boolean isAccountNonLocked() {
		//判断用户是否被锁定,默认为true,生产环境视情况修改,赋值
		return true;
	}
	@Override
	public boolean isCredentialsNonExpired() {
		//判断用户凭证是否过期,默认为true,生产环境视情况修改,赋值
		return true;
	}
	@Override
	public boolean isEnabled() {
		//判断用户是否启用,默认为true,生产环境视情况修改,赋值
		return true;
	}
	
}

然后我们看最重要的授权配置

3.3.1 内存存储

3.3.2jwt 存储
3.3.3redis 存储

SecurityConfig.java

主要看这里

	@GetMapping("/user-me")
    public Principal user(Principal member) {
        //获取当前用户信息
        return member;
    }

4.演示效果

这里我用的是 postman 模拟请求

4.1 请求授权服务

1.请求 token

此处输入图片的描述

2.刷新 token

此处输入图片的描述

4.2 请求 A 服务

1.请求 anon 公开接口

此处输入图片的描述

2.请求 test2 接口(拥有 admin 角色才可以)

此处输入图片的描述

2.请求 test1 接口(拥有 user 角色才可以)

此处输入图片的描述

5.添加 zuul 网关

zuul 网关最好的就是只做路由,具体的权限还是由各自的资源服务器处理,个人理解,不喜勿喷

@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
    }
}
spring:
  application:
    name: oauth-zuul
server:
  port: 9030
eureka:
  instance:
    prefer-ip-address: true #使用IP注册
    instance-id: ${spring.application.name}:${server.port}
  client:
      service-url:
        defaultZone: http://localhost:8761/eureka/
zuul:
  host:
    connect-timeout-millis: 10000
    socket-timeout-millis: 60000
  routes:
    oauth-center:
      path: /uaa/**
      strip-prefix: true
      sensitiveHeaders:
      serviceId: oauth-center
    oauth-a:
      path: /oa/**
      strip-prefix: true
      sensitiveHeaders:
      serviceId: oauth-a
security:
  oauth2:
    client:
      access-token-uri: http://localhost:9030/uaa/oauth/token ##网关的地址
      user-authorization-uri: http://localhost:9030/uaa/oauth/authorize
      #client-id: system #OAuth2客户端ID
      #client-secret: system #OAuth2客户端密钥
    resource:
      user-info-uri:  http://localhost:9030/uaa/user/user-me
      prefer-token-info: false
      #jwt:
        #key-value: 0123456789 #使

gitee 源码地址

  • 云计算
    78 引用 • 91 回帖 • 1 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 18 关注
  • 鉴权
    2 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...