当前位置:   article > 正文

springcloud-alibaba springSecurity整合oauth2 授权码模式_springcloudalibaba集成security

springcloudalibaba集成security

OAuth的思路

OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(authorization layer)。“客户端"不能直接登录"服务提供商”,只能登录授权层,以此将用户与客户端区分开来。"客户端"登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。

"客户端"登录授权层以后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料

OAuth 2.0的运行流程如下图,摘自RFC 6749。
在这里插入图片描述
(A)用户打开客户端以后,客户端要求用户给予授权。

(B)用户同意给予客户端授权。

(C)客户端使用上一步获得的授权,向认证服务器申请令牌。

(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。

(E)客户端使用令牌,向资源服务器申请获取资源。

(F)资源服务器确认令牌无误,同意向客户端开放资源。

概述

Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架。它是保护基于 Spring 的应用程序的事实标准。

Spring Security 是一个专注于为 Java 应用程序提供身份验证和授权的框架。像所有 Spring 项目一样,Spring Security 的真正强大之处在于它可以轻松扩展以满足自定义需求

特征

  • 对身份验证和授权的全面且可扩展的支持
  • 防止会话固定、点击劫持、跨站点请求伪造等攻击
  • Servlet API 集成
  • 与 Spring Web MVC 的可选集成

工作原理
在这里插入图片描述

  1. 客户端发起一个请求,进入 Security 过滤器链。
  2. 当到 LogoutFilter 的时候判断是否是登出路径,如果是登出路径则到 logoutHandler ,如果登出成功则到logoutSuccessHandler 登出成功处理,如果登出失败则由 ExceptionTranslationFilter;如果不是登出路径则直接进入下一个过滤器。
  3. 当到 UsernamePasswordAuthenticationFilter的时候判断是否为登录路径,如果是,则进入该过滤器进行登录操作,如果登录失败则到 AuthenticationFailureHandler登录失败处理器处理,如果登录成功则到 AuthenticationSuccessHandler登录成功处理器处理,如果不是登录请求则不进入该过滤器。
  4. 当到 FilterSecurityInterceptor 的时候会拿到 uri ,根据 uri去找对应的鉴权管理器,鉴权管理器做鉴权工作,鉴权成功则到 Controller 层否则到 AccessDeniedHandler鉴权失败处理器处理。

OAuth 2.0授权框架定义了四种标准授权类型:授权码、隐式、资源所有者密码凭据和客户端凭据
AuthorizationGrantType
1.implicit
2.refresh_token
3.client_credentials
4.password
在这里插入图片描述
OAuth 定义了四个角色:

  • resource owner(资源所有者)

    能够授予对受保护资源的访问权限的实体。
    当资源所有者是一个人时,它被称为
    最终用户。

  • resource server(资源服务器)

    托管受保护资源的服务器,能够使用访问令牌接受
    和响应受保护资源请求。

  • client(客户端)

    代表
    资源所有者并经其授权发出受保护资源请求的应用程序。“客户”一词确实
    不暗示任何特定的实现特征(例如,
    应用程序是否在服务器、桌面或其他
    设备上执行)。

  • authorization server(授权服务器)
    服务器 在成功验证资源所有者并获得授权
    后向客户端颁发访问令牌。
    授权服务器和资源服务器之间的交互
    超出了本规范的范围。授权服务器
    可以是与资源服务器相同的服务器,也可以是单独的实体。
    单个授权服务器可以发布多个资源服务器
    接受的访问令牌。

授权码流程
流程包括以下步骤:

  • (A) 客户端通过将资源所有者的用户代理定向到授权端点来
    启动流程。客户端包括
    其客户端标识符、请求的范围、本地状态和 一旦授予
    (或拒绝)访问权限 ,授权服务器会将用户
     代理发送回该URI
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • (B) 授权服务器验证资源所有者(通过用户代理 )
    并确定资源所有者是允许还是拒绝客户端的访问请求。
    
    • 1
    • 2
  • (C) 假设资源所有者授予访问权限,授权服务器使用
    之前提供的重定向 URI(在请求中或在
    客户端注册期间)
    将用户代理重定向回客户端。重定向 URI 包括
    授权代码和客户端
    之前提供的任何本地状态。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • (D) 客户端通过包含
    在上一步中收到
    的授权码,从授权服务器的令牌端点请求访问令牌。发出请求时,
    客户端向授权服务器进行身份验证。客户端
    包含用于获取授权的重定向URI验证码。
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • (E) 授权服务器对客户端进行身份验证,验证
    授权码,并确保接收到的重定向 URI与步骤 (C)
    中用于重定向客户端的 URI 匹配。如果有效,授权
    服务器 将使用访问令牌和可选的刷新令牌进行响应
    。
    . 授权请求客户端通过
    使用“application/x-www-form-urlencoded”格式
    将以下参数添加到授权端点 URI 的查询组件来构造请求 URI
    ,
    response_type
    REQUIRED.  Value MUST be set to "code".
    
    client_id
    REQUIRED.  The client identifier as described in Section 2.2.
    
    redirect_uri
    OPTIONAL.  As described in Section 3.1.2.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

令牌端点TokenEndpoint
授权端点 AuthorizationEndpoint
用户授权提交端点 WhitelabelApprovalEndpoint

在这里插入图片描述

  1. 用户提交用户名、密码被SecurityFilterChain中的 UsernamePasswordAuthenticationFilter 过滤器获取到, 封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
  2. 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
  3. 认证成功后, AuthenticationManager 身份管理器返回一个被填充满了信息的(包括上面提到的权限信息, 身份信息,细节信息,但密码通常会被移除) Authentication 实例。
  4. SecurityContextHolder 安全上下文容器将第3步填充了信息的 Authentication ,通过 SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。 可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它 的实现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个 List 列表,存放多种认证方式,最终实际的认证工作是由 AuthenticationProvider完成的。咱们知道web表单的对应的AuthenticationProvider实现类为 DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终 AuthenticationProvider将UserDetails填充至Authentication。
  5. UserDetailsService校验用户信息
  6. PasswordEncoder会去把数据库查到的密码(一般都是加盐后加密的密码)去进行校验(检查明文密码是否与之前的哈希值匹配)

JWT内容增强器配置
实现TokenEnhancer接口

package com.macro.mall.auth.component;

import com.macro.mall.auth.domain.SecurityUser;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * JWT内容增强器
 * Created by macro on 2020/6/19.
 */
@Component
public class JwtTokenEnhancer implements TokenEnhancer {
    /**
     * 在创建供客户端使用的新令牌的过程中,提供定制访问令牌的机会(例如,通过其附加信息映射)。
     * @param accessToken 当前访问令牌及其过期和刷新令牌
     * @param authentication 当前身份验证
     * @return 包括客户端和用户详细信息
     */
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();
        Map<String, Object> info = new HashMap<>();
        //把用户ID设置到JWT中
        info.put("id", securityUser.getId());
        info.put("client_id",securityUser.getClientId());
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
        return accessToken;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

SpringSecurity配置
继承WebSecurityConfigurerAdapter启动注解@EnableWebSecurity 打开security安全配置

package com.macro.mall.auth.config;

import org.aspectj.weaver.ast.And;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * SpringSecurity配置
 * Created by macro on 2020/6/19.
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        包含所有执行器端点的匹配器。它还包括链接端点,该端点位于执行器端点的基本路径上
//        匹配"/rsa/publicKey"和"/v2/api-docs"规则的放行其他的都需要通过身份验证
        http.authorizeRequests()
                .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
                .antMatchers("/rsa/publicKey").permitAll()
                .antMatchers("/v2/api-docs").permitAll()
                .anyRequest().authenticated();
//      授权码模式必须配置 http.httpBasic();
        http.httpBasic();

    }

    @Bean
    @Override
    /**
     * 身份验证管理器
     */
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
   /**
   密码编码器
    */
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

AuthorizationServerTokenServices设置令牌策略
也可以直接在ClientDetailsServiceConfigurer 里面设置
认证服务器配置继承AuthorizationServerConfigurerAdapter 启动注解@EnableAuthorizationServer 打开授权服务器

package com.macro.mall.auth.config;


import com.macro.mall.auth.component.JwtTokenEnhancer;
import com.macro.mall.auth.component.WhitelabelApprovalEndopintHandler;
import com.macro.mall.auth.service.impl.UserServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
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.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;

import javax.xml.ws.Service;
import java.security.KeyPair;
import java.util.ArrayList;
import java.util.List;

/**
 * 认证服务器配置
 * Created by macro on 2020/6/19.
 */
@AllArgsConstructor
@Configuration
@EnableAuthorizationServer
public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {

    private final PasswordEncoder passwordEncoder;
    private final UserServiceImpl userDetailsService;
    private final AuthenticationManager authenticationManager;
    private final JwtTokenEnhancer jwtTokenEnhancer;
    private final ClientDetailsService clientDetailsService;

    @Bean
    public AuthorizationCodeServices AuthorizationCodeServices(){
        return new InMemoryAuthorizationCodeServices();
    }

    @Bean
    public WhitelabelApprovalEndopintHandler whitelabelApprovalEndopintHandler(){
        return new WhitelabelApprovalEndopintHandler();
    }

    @Bean
//    令牌存储
    public TokenStore tokenStore(){
        return new InMemoryTokenStore();
    }

/*    @Bean
    public AuthorizationServerTokenServices tokenServices(){
        DefaultTokenServices tokenServices=new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore());
//        客户端配置策略
        tokenServices.setClientDetailsService(clientDetailsService);
//        支持令牌的刷新
        tokenServices.setSupportRefreshToken(true);
        return tokenServices;
    }*/
    /**
     * 客户端详情配置
     * 装载Endpoints所有相关的类配置(AuthorizationServer、TokenServices、TokenStore、ClientDetailsService、UserDetailsService)。
     * http://localhost:8201/mall-auth/oauth/authorize?response_type=code&client_id=admin-app&redirect_uri=https://www.baidu.com&scope=all
     * 授权码模式
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("admin-app")
//                加盐
                .secret(passwordEncoder.encode("123456"))
                //权限
                .scopes("all","username")
                // 配置 authorization code grant type 配置多个授权模式
                .authorizedGrantTypes("password", "refresh_token","authorization_code")
                //token有效期
                .accessTokenValiditySeconds(3600*24)
                //刷新token有效期
                .refreshTokenValiditySeconds(3600*24*7)
                .autoApprove(false)
                .redirectUris("http://localhost:8201/callback")
                .and()
                .withClient("portal-app")
                .secret(passwordEncoder.encode("123456"))// 加盐
                .scopes("all","username")
                .authorizedGrantTypes("password", "refresh_token")
                .accessTokenValiditySeconds(3600*24)
                .refreshTokenValiditySeconds(3600*24*7);
    }

    @Override
    //令牌端点服务配置
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//      令牌增强器链
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> delegates = new ArrayList<>();
        delegates.add(jwtTokenEnhancer);
        delegates.add(accessTokenConverter());
        enhancerChain.setTokenEnhancers(delegates); //配置JWT的内容增强器
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService) //配置加载用户信息的服务
                .accessTokenConverter(accessTokenConverter())
                .authorizationCodeServices(AuthorizationCodeServices())
                .tokenStore(tokenStore())
//                .tokenServices(tokenServices())
//                .pathMapping("/oauth/authorize","/mall-auth/oauth/authorize")
                .tokenEnhancer(enhancerChain);

    }

    @Override
//    允许客户端进行表单验证 令牌端点安全约束配置
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.
//                允许客户端进行表单验证client_id和client_secret做登录认证
                allowFormAuthenticationForClients();
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setKeyPair(keyPair()); //设置公钥
        return jwtAccessTokenConverter;
    }

    @Bean
    public KeyPair keyPair() {
        //从classpath下的证书中获取秘钥对
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray());
        return keyStoreKeyFactory.getKeyPair("jwt", "123456".toCharArray());
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148

授权controller,我这里因为是用的微服务架构 getway里面 会默认带一个server_name 会导致授权码模式 不能正常跳转到指定的URI上面
比如请求地址是http://localhost:8201/mall-auth/oauth/authorize?response_type=code&client_id=admin-app&scope=all
授权成功后
会直接跳转到http://localhost:8201:/oauth/authorize
所以我自己定义了一个授权方法 和底层WhitelabelApprovalEndpoint写的差不多 只不过我把下面这段代码注释了
你们如果没有用到getway可以 直接使用默认的不需要重写 /confirm_access 授权请求

在这里插入图片描述

package com.macro.mall.auth.controller;

import com.macro.mall.auth.component.WhitelabelApprovalEndopintHandler;
import com.macro.mall.auth.domain.Oauth2TokenDto;
import com.macro.mall.common.api.CommonResult;
import com.macro.mall.common.constant.AuthConstant;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.servlet.ModelAndView;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.Map;

/**
 * 自定义Oauth2获取令牌接口
 * Created by macro on 2020/7/17.
 */
@Controller
@Api(tags = "AuthController", description = "认证中心登录认证")
@RequestMapping("/oauth")
@SessionAttributes("authorizationRequest")
public class AuthController {

    @Autowired
//    令牌处理器
    private TokenEndpoint tokenEndpoint;

    @Autowired
//    授权处理器
    private AuthorizationEndpoint authEndpoint;

    @Autowired
    WhitelabelApprovalEndopintHandler whitelabelApprovalEndopintHandler;

    @ApiOperation("Oauth2获取token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "grant_type", value = "授权模式", required = true),
            @ApiImplicitParam(name = "client_id", value = "Oauth2客户端ID", required = true),
            @ApiImplicitParam(name = "client_secret", value = "Oauth2客户端秘钥", required = true),
            @ApiImplicitParam(name = "refresh_token", value = "刷新token"),
            @ApiImplicitParam(name = "username", value = "登录用户名"),
            @ApiImplicitParam(name = "password", value = "登录密码")
    })
    @RequestMapping(value = "/token", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<Oauth2TokenDto> postAccessToken(@ApiIgnore Principal principal, @ApiIgnore @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal,parameters).getBody();
        Oauth2TokenDto oauth2TokenDto = Oauth2TokenDto.builder()
                .token(oAuth2AccessToken.getValue())
                .refreshToken(oAuth2AccessToken.getRefreshToken().getValue())
                .expiresIn(oAuth2AccessToken.getExpiresIn())
                .tokenHead(AuthConstant.JWT_TOKEN_PREFIX).build();

        return CommonResult.success(oauth2TokenDto);
    }

    /**
     * 授权端点
     * @param model
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping("/confirm_access")
    public ModelAndView getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception{
       return whitelabelApprovalEndopintHandler.getAccessConfirmation(model,request);


    }


}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86

重写WhitelabelApprovalEndopint 授权处理器

package com.macro.mall.auth.component;

import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.util.HtmlUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @author Xuyijun
 * @classname WhitelabelApprovalEndopintHandler.java
 * 授权处理器
 * @create 2022-02-17, 星期四, 13:38:29
 */

public class WhitelabelApprovalEndopintHandler {


    public ModelAndView getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception {
        final String approvalContent = createTemplate(model, request);
        if (request.getAttribute("_csrf") != null) {
            model.put("_csrf", request.getAttribute("_csrf"));
        }
        View approvalView = new View() {
            @Override
            public String getContentType() {
                return "text/html";
            }

            @Override
            public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
                response.setContentType(getContentType());
                response.getWriter().append(approvalContent);
            }
        };
        return new ModelAndView(approvalView, model);
    }

    protected String createTemplate(Map<String, Object> model, HttpServletRequest request) {
        AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get("authorizationRequest");
        String clientId = authorizationRequest.getClientId();

        StringBuilder builder = new StringBuilder();
        builder.append("<html><body><h1>OAuth Approval</h1>");
        builder.append("<p>Do you authorize \"").append(HtmlUtils.htmlEscape(clientId));
        builder.append("\" to access your protected resources?</p>");
        builder.append("<form id=\"confirmationForm\" name=\"confirmationForm\" action=\"");

        /*String requestPath = ServletUriComponentsBuilder.fromContextPath(request).build().getPath();
        if (requestPath == null) {
            requestPath = "";
        }*/
        String requestPath="/mall-auth";
        builder.append(requestPath).append("/oauth/authorize\" method=\"post\">");
        builder.append("<input name=\"user_oauth_approval\" value=\"true\" type=\"hidden\"/>");

        String csrfTemplate = null;
        CsrfToken csrfToken = (CsrfToken) (model.containsKey("_csrf") ? model.get("_csrf") : request.getAttribute("_csrf"));
        if (csrfToken != null) {
            csrfTemplate = "<input type=\"hidden\" name=\"" + HtmlUtils.htmlEscape(csrfToken.getParameterName()) +
                    "\" value=\"" + HtmlUtils.htmlEscape(csrfToken.getToken()) + "\" />";
        }
        if (csrfTemplate != null) {
            builder.append(csrfTemplate);
        }

        String authorizeInputTemplate = "<label><input name=\"authorize\" value=\"Authorize\" type=\"submit\"/></label></form>";

        if (model.containsKey("scopes") || request.getAttribute("scopes") != null) {
            builder.append(createScopes(model, request));
            builder.append(authorizeInputTemplate);
        } else {
            builder.append(authorizeInputTemplate);
            builder.append("<form id=\"denialForm\" name=\"denialForm\" action=\"");
            builder.append(requestPath).append("/oauth/authorize\" method=\"post\">");
            builder.append("<input name=\"user_oauth_approval\" value=\"false\" type=\"hidden\"/>");
            if (csrfTemplate != null) {
                builder.append(csrfTemplate);
            }
            builder.append("<label><input name=\"deny\" value=\"Deny\" type=\"submit\"/></label></form>");
        }

        builder.append("</body></html>");

        return builder.toString();
    }

    private CharSequence createScopes(Map<String, Object> model, HttpServletRequest request) {
        StringBuilder builder = new StringBuilder("<ul>");
        @SuppressWarnings("unchecked")
        Map<String, String> scopes = (Map<String, String>) (model.containsKey("scopes") ?
                model.get("scopes") : request.getAttribute("scopes"));
        for (String scope : scopes.keySet()) {
            String approved = "true".equals(scopes.get(scope)) ? " checked" : "";
            String denied = !"true".equals(scopes.get(scope)) ? " checked" : "";
            scope = HtmlUtils.htmlEscape(scope);

            builder.append("<li><div class=\"form-group\">");
            builder.append(scope).append(": <input type=\"radio\" name=\"");
            builder.append(scope).append("\" value=\"true\"").append(approved).append(">Approve</input> ");
            builder.append("<input type=\"radio\" name=\"").append(scope).append("\" value=\"false\"");
            builder.append(denied).append(">Deny</input></div></li>");
        }
        builder.append("</ul>");
        return builder.toString();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

资源服务器我是在getway做的 这里就不写了

http://localhost:8201/mall-auth/oauth/authorize?response_type=code&client_id=admin-app&scope=all
访问
因为我配置了多个 ,选一个 点击授权即可
在这里插入图片描述

然后可以看到后面code
在这里插入图片描述

打开postman
http://localhost:8201/mall-auth/oauth/token?grant_type=authorization_code&code=Sq4mTN&redirect_uri=http://localhost:8201/callback&scope=all&client_id=admin-app&client_secret=123456

post请求
在这里插入图片描述
返回成功
在这里插入图片描述
参考链接
Oauth2认证流程官方文档https://tools.ietf.org/html/rfc6749#section-1.3
spring security 整合oauth2
oauth自定义登录页面和授权页面

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/68810
推荐阅读
相关标签
  

闽ICP备14008679号