Spring Security OAuth架构简介

194 阅读2分钟

这是我参与「掘金日新计划 · 6 月更文挑战」的第30天 ,点击查看活动详情

Spring Security OAuth架构简介

1、服务器端点

  • 授权端点:生成授权码code\

  • Token端点:颁发access_token\

  • 校验端点:校验access_token\

  • 吊销端点:主动吊销非法access_token\

2、Spring Security OAuth架构

(1)用户访问客户应用程序,经过过滤器验证,如果没有权限则执行步骤(2),如果有权限则执行正常的业务逻辑(service层)

(2)如果没有权限则访问授权服务器的授权端点,授权端点调用Spring Security OAuth提供的工具类生成授权码

(3)用户获得授权码后使用OAuth2RestTemplate请求授权服务器颁发access_token,授权服务器Token端点调用Spring Security OAuth提供的工具类生成access_token

(4)用户获得access_token后使用OAuth2RestTemplate向资源服务器请求资源,此时资源服务器上的ResourceServerTokenService会执行对access_token的校验,同时access_tokenOAuth2AuthenticationManager会从中获取用户的相关信息

密码模式(Resource Owner Password Credentials)与授权码模式的区别是申请令牌不再使用授权码,而是直接通过用户名和密码即可申请令牌。

一、修改授权服务器配置

1、修改OAuth2AuthorizationServer

使其可以同时接受授权码和密码模式

 

// 添加商户信息
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    ......
        // 同时支持授权码模式和密码模式
        .authorizedGrantTypes("authorization_code", "password")
   ......
}

\

2、发送请求获取令牌

Post请求:http://localhost:8081/oauth/token

参数列表如下:\

  • grant_type:密码模式授权填写password
  • username:账号 
  • password:密码 并且此链接需要使用 http Basic认证。

\

二、如何从数据库获取用户信息

1、创建业务层

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@Service("userDetailsServiceImpl")
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    ClientDetailsService clientDetailsService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //***********以下为授权码模式
        //取出商户身份,如果身份为空说明没有认证
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //没有认证统一采用httpbasic认证,httpbasic中存储了client_id和client_secret,开始认证client_id和client_secret
        if(authentication==null){
            ClientDetails clientDetails = clientDetailsService.loadClientByClientId(username);
            if(clientDetails!=null){
                //密码
                String clientSecret = clientDetails.getClientSecret();
                return new User(username,clientSecret,AuthorityUtils.commaSeparatedStringToAuthorityList(""));
            }
        }
        
        
        //***********以下为用户名密码模式
        if (StringUtils.isEmpty(username)) {
            return null;
        }
       
        System.out.println(username);
        //取出正确密码(hash值)
        String password = "123456";
        //使用用户名和密码去数据库校验,校验成功则放行否则返回null校验失败
        if(!"helen".equals(username) || !"123456".equals(password)){
            return null;
        }
        //用户权限,这里暂时使用静态数据,最终会从数据库读取
        UserDetails userDetails = new User(username,
                new BCryptPasswordEncoder().encode("123456"),
                AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_A, ROLE_B, ROLE_C"));
        return userDetails;
    }
}

2、修改授权服务器配置

OAuth2AuthorizationServer
屏蔽之前的UserDetailsService的创建,如下

 

@Bean
UserDetailsService userDetailsService(){
        ......
}

修改之前的注入,注入自定义的业务层实现

 

//注入用户信息
//@Autowired
@Resource(name = "userDetailsServiceImpl")
UserDetailsService userDetailsService;