OAuth2认证和授权:ClientCredentials认证

1:创建授权服务器项目:AuthorizationServer,添加包:IdentityServer4

2:创建资源服务器项目:ResourcesServer,添加包:IdentityServer4.AccesstokenValidation

3:创建请求客户端项目:ClientCredentials,添加包:IdentityModel

 

AuthorizationServer代码示例:

  public class Config
    {
        /// <summary>
        /// 定义用户可以访问的资源
        /// </summary>
        /// <returns></returns>
        public static List<ApiResource> GetApiResources()
        {
            return new List<ApiResource> {
                /*
                 具有单个作用域的简单API,这样定义的话,作用域(scope)和Api名称(ApiName)相同
                 */
                new ApiResource("api","描述"),

                 //如果需要更多控制,则扩展版本
                new ApiResource{
                    Name="userinfo", //资源名称,对应客户端的:ApiName,必须是唯一的
                    Description="描述",
                    DisplayName="", //显示的名称
                  
                    //ApiSecrets =
                    //{
                    //    new Secret("secret11".Sha256())
                    //},

                    //作用域,对应下面的Cliet的 AllowedScopes
                    Scopes={
                        new Scope
                        {
                            Name = "apiInfo.read_full",
                            DisplayName = "完全的访问权限",
                            UserClaims={ "super" }
                        },
                        new Scope
                        {
                            Name = "apiinfo.read_only",
                            DisplayName = "只读权限"
                        }
                    },
                },
            };
        }

        /// <summary>
        /// 客户端合法性验证
        /// </summary>
        /// <returns></returns>
        public static List<Client> GetClients()
        {
            #region 客户端模式 ClientCredentials
            var ClientCredentials = new Client
            {

                /******************客户端 请求对应的字段*******************
                 client_id:客户端的ID,必选
                 grant_type:授权类型,必选,此处固定值“code”
                 client_secret:客户端的密码,必选
                 scope:申请的权限范围,可选,如果传了必须是正确的,否则也不通过
                 ************************************/

                //这个Client集合里面,ClientId必须是唯一的
                ClientId = "780987652", // 客户端ID,客户端传过来的必须是这个,验证才能通过,
                AllowedGrantTypes = GrantTypes.ClientCredentials,// 授权类型,指客户端可以使用的模式
                ClientSecrets = { new Secret("secret".Sha256()) }, //客户端密钥
                //ClientSecrets={new Secret("secret".Sha512()) },
                //RequireClientSecret = false, //不验证secret ,一般是信得过的第三方

                ClientName = "客户端名称",
                Description = "描述",
                //Claims = new List<Claim> {
                //    new Claim("super","super")
                //},
                /*
                 权限范围,对应的ApiResouce,这里是客户端模式,对应的是用户资源,所以是ApiResouce
                 如果是oidc 这对应的是identityResouece,身份资源
                 所以是取决于AllowedGrantTypes的类型

                允许客户端访问的API作用域
                 */
                AllowedScopes = { "apiInfo.read_full" } //
            };

            var ClientCredentials1 = new Client
            {
                ClientId = "userinfo",
                AllowedGrantTypes = GrantTypes.ClientCredentials, //客户端输入:client_credentials
                ClientSecrets = { new Secret("secret".Sha256()) },
                ClientName = "客户端名称",
                AllowedScopes = { "apiInfo.read_full" } //
            };
            #endregion
            #region 密码模式 ResourceOwnerPassword
            var pwd = new Client
            {
                ClientId = "userinfo_pwd",
                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,//客户端输入:password
                ClientSecrets = { new Secret("secret".Sha256()) },
                ClientName = "客户端名称",
                RefreshTokenUsage = TokenUsage.ReUse,
                AlwaysIncludeUserClaimsInIdToken = true,
                AllowOfflineAccess = true,
                AllowedScopes = { "apiInfo.read_full" } //
            };
            #endregion

            return new List<Client> {
               ClientCredentials,
               //ClientCredentials1,
               //pwd,
           };
        }


        /// <summary>
        /// 密码模式,需要用的到用户名和密码,正式操作是在数据库中找
        /// </summary>
        /// <returns></returns>
        public static List<TestUser> GetTestUsers()
        {
            return new List<TestUser> {
                new TestUser
                {
                    SubjectId="100000", //用户ID
                    Username="cnblogs", //用户名
                    Password="123", //密码
                    Claims=new List<Claim>{
                        new Claim("name","name")
                    }
                }
            };
        }
    }

 

Startup.cs配置:

public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            //注册ids中间件
            services.AddIdentityServer()
               //设置开发者临时签名凭据
               .AddDeveloperSigningCredential()
               
               //in-men 方式把信息添加到内存中
               .AddInMemoryApiResources(Config.GetApiResources())
               .AddInMemoryClients(Config.GetClients())
               .AddTestUsers(Config.GetTestUsers());

        }

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
  //使用ids中间件
            app.UseIdentityServer();
}

 

ResourcesServer 资源服务器认证示例:

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            //默认的认证方式是Bearer认证
            services.AddAuthentication("Bearer")
            //配置要验证的信息
            .AddIdentityServerAuthentication(options =>
            {
                //令牌或者说AccessToken颁发的地址,Token中会包含该地址
                //第一次会去认证服务器获取配置信息
                options.Authority = "http://localhost:5003"; //必填
                options.ApiName = "userinfo";
                options.ApiSecret = "secret";
                //options.SaveToken = true;
                options.RequireHttpsMetadata = false;//暂时取消Https验证,
            });

            //services.AddAuthorization(options => {
            //    options.AddPolicy("client", policy => policy.RequireClaim("client_id"));
            //});
        }
 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
 app.UseAuthentication();

}

 

 

资源接口:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Linq;

namespace ResourcesServer.Controllers
{
    [Route("identity")]
    [Authorize]
    public class IdentityController : ControllerBase
    {
        /// <summary>
        /// 获取当前的信息
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult Get()
        {
            return new JsonResult(User.Claims.Select(
                c => new { c.Type, c.Value }));
        }

        [HttpGet]
        [Route("userInfo")]
        public ActionResult GetUserInfo()
        {
            return new JsonResult(User.Claims.Select(
                c => new { c.Type, c.Value }));
        }
      
    }
}

 

通过Postman请求授权服务器获取access_token

参数:

client_id:780987652
client_secret:secret
grant_type:client_credentials

 

 

 然后通过该access_token 请求资源服务器获取资源

 

nbf:非必须。not before。如果当前时间在nbf里的时间之前,则Token不被接受;一般都会留一些余地,比如几分钟。

exp:#非必须。expire 指定token的生命周期。unix时间戳格式

iss:#非必须。issuer 请求实体,可以是发起请求的用户的信息,也可是jwt的签发者。

aud:#非必须。接收该JWT的一方。

详细信息参考:https://www.cnblogs.com/zjutzz/p/5790180.html

 

可以把access_token放到jwt.io 看下:

 

 可以通过 http://localhost:5003/.well-known/openid-configuration 查看配置信息

ClientCredentials第三方代码请求方式:

using IdentityModel;
using IdentityModel.Client;
using Newtonsoft.Json.Linq;
using System;
using System.Net.Http;
using System.Text;

namespace ClientCredentials
{
    /// <summary>
    /// 客户端模式,请求授权服务器获取token,请求资源服务器获取资源
    /// 依赖包:IdentityModel
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            string Authority = "http://localhost:5003";
            string ApiResurce = "http://localhost:5002/";
            var tokenCliet = new HttpClient()
            {
                BaseAddress = new Uri(ApiResurce)
            };

            /*
             这样做的目的是:
             资源服务器会去授权服务器认证,所以在客户端可以先判断下授权服务器是否挂了
             */
            DiscoveryCache _cache = new DiscoveryCache(Authority);
            var disco1 =  _cache.GetAsync().Result;
            if (disco1.IsError) throw new Exception(disco1.Error);
            //或者
            var disco = tokenCliet.GetDiscoveryDocumentAsync(Authority).Result;
            if (disco.IsError) throw new Exception(disco.Error);


            var response = tokenCliet.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,
                ClientId = "780987652",
                ClientSecret= "secret",
                //GrantType= "client_credentials"
            }).Result;

            if (response.IsError) throw new Exception(response.Error);

            var token = response.AccessToken;

            //把token,Decode
            if (response.AccessToken.Contains("."))
            {
                //Console.WriteLine("\nAccess Token (decoded):");
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("\nAccess Token (decoded):");
                Console.ResetColor();

                var parts = response.AccessToken.Split('.');
                var header = parts[0];
                var claims = parts[1];

                Console.WriteLine(JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(header))));
                Console.WriteLine(JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(claims))));
            }
            //设置请求的Token
            tokenCliet.SetBearerToken(token);
            //请求并返回字符串
            var apiResource1 = tokenCliet.GetStringAsync("identity").Result;
            var userinfo = tokenCliet.GetStringAsync("identity/userinfo").Result;

           var j =  JObject.Parse(userinfo);
            //或者
            var getVal = tokenCliet.GetAsync("api/values").Result;
            if (getVal.IsSuccessStatusCode)
            {
                Console.WriteLine(getVal.Content.ReadAsStringAsync().Result);
            }
            Console.ReadLine();
        }
    }
}

 

 Access Token (decoded)的结果

 

 

转载于:https://www.cnblogs.com/nsky/p/10349146.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于Spring Security OAuth2的认证授权代码示例: 1. 添加Maven依赖 ```xml <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.4.0.RELEASE</version> </dependency> ``` 2. 配置OAuth2服务器 ```java @Configuration @EnableAuthorizationServer public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private DataSource dataSource; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } } ``` 3. 配置资源服务器 ```java @Configuration @EnableResourceServer public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated(); } } ``` 4. 配置Spring Security ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/oauth/**").permitAll().anyRequest().authenticated().and().csrf().disable(); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } ``` 5. 配置数据源 ```java @Configuration public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } } ``` 6. 配置应用属性 ```properties spring.datasource.url=jdbc:mysql://localhost:3306/oauth2 spring.datasource.username=root spring.datasource.password=root security.oauth2.client.client-id=client security.oauth2.client.client-secret=secret security.oauth2.client.access-token-validity-seconds=3600 security.oauth2.client.authorized-grant-types=authorization_code,refresh_token,password,client_credentials security.oauth2.client.scope=read,write security.oauth2.resource.id=resource security.user.name=user security.user.password=password security.user.roles=USER ``` 以上代码仅供参考,具体实现需要根据实际场景进行调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值