I have the following three tables,
Region Table,
RegionId
RegionName
1
Admin
2
North Region
3
South Region
Branch Table
BranchId
BranchName
FkRegionId
1
Roswell Rd
3
2
Test
2
3
Piedmont Ave
2
4
Ashford Dunwoody
1
User Table
UserId
FirstName
FkBranchId
1
Hasa
9
2
Jane
1
3
Joyce
7
4
Jane
1
5
John
3
6
Sharon
8
As mentioned above, each branch has its region and each user has a branch. I need to create following JSON for my frond-end usage. Therefore I need to populate data in order to create this JSON.
Region1
Branch1
Jane
Paul
Alex
Branch2
Neil
Kaja
Alex
Region2
Branch4
Ama
Hema
Ira
Branch5
Laura
Tim
Yea
How can I do this using C# and linq?
You need to use Linq Join and GroupBy as following:
var regions = new List<Region>()
{
new Region() { RegionId = 1, RegionName = "Admin" },
new Region() { RegionId = 2, RegionName = "North Region" },
new Region() { RegionId = 3, RegionName = "South Region" }
};
var branchs = new List<Branch>()
{
new Branch() {BranchId = 1, BranchName = "Roswell Rd", FkRegionId = 3},
new Branch() {BranchId = 2, BranchName = "Test", FkRegionId = 2},
new Branch() {BranchId = 3, BranchName = "Piedmont Ave ", FkRegionId = 2},
new Branch() {BranchId = 4, BranchName = "Ashford Dunwoody ", FkRegionId = 1},
};
var users = new List<User>()
{
new User() {UserId = 1, FirstName = "Hasa", FkBranchId = 9},
new User() {UserId = 2, FirstName = "Jane", FkBranchId = 1},
new User() {UserId = 3, FirstName = "Joyce", FkBranchId = 7},
new User() {UserId = 4, FirstName = "Jane", FkBranchId = 1},
new User() {UserId = 5, FirstName = "John", FkBranchId = 3},
new User() {UserId = 6, FirstName = "Sharon", FkBranchId = 8},
};
var tree = from user in users
join branch in branchs on user.FkBranchId equals branch.BranchId
join region in regions on branch.FkRegionId equals region.RegionId
group region by new { region.RegionId, branch.BranchId } into grp
select new
{
RegionName = regions.FirstOrDefault(s => s.RegionId == grp.Key.RegionId).RegionName,
Branchs = new
{
BranchName = branchs.FirstOrDefault(s => s.FkRegionId == grp.Key.RegionId).BranchName,
Users = users.Where(i => i.FkBranchId == grp.Key.BranchId).Select(s => new
{
FirstName = s.FirstName
})
}
};
var json = JsonConvert.SerializeObject(tree, Formatting.Indented);
This will give you an expected result:
[
{
"RegionName": "South Region",
"Branchs": {
"BranchName": "Roswell Rd",
"Users": [
{
"FirstName": "Jane"
},
{
"FirstName": "Jane"
}
]
}
},
{
"RegionName": "North Region",
"Branchs": {
"BranchName": "Test",
"Users": [
{
"FirstName": "John"
}
]
}
}
]
var jsonResponse = "[{\"UserId\":195,\"FirstName\":\"Carlton\",\"BranchId\":4,\"BranchName\":\"Test\",\"RegionId\":1,\"RegionName\":\"Admin\"},{\"UserId\":223,\"FirstName\":\"Lorenza\",\"BranchId\":4,\"BranchName\":\"Test\",\"RegionId\":1,\"RegionName\":\"Admin\"},{\"UserId\":163,\"FirstName\":\"Alice\",\"BranchId\":17,\"BranchName\":\"Ratnapura\",\"RegionId\":1,\"RegionName\":\"Admin\"},{\"UserId\":264,\"FirstName\":\"Karen\",\"BranchId\":7,\"BranchName\":\"Peachtree\",\"RegionId\":3,\"RegionName\":\"South Region\"},{\"UserId\":266,\"FirstName\":\"Starla\",\"BranchId\":7,\"BranchName\":\"Peachtree\",\"RegionId\":3,\"RegionName\":\"South Region\"},{\"UserId\":30,\"FirstName\":\"Jane\",\"BranchId\":9,\"BranchName\":\"Henderson Mill\",\"RegionId\":3,\"RegionName\":\"South Region\"}]";
var myDeserializedClass = JsonConvert.DeserializeObject < List < Root >> (jsonResponse);
var jsonResponseList = myDeserializedClass.GroupBy(item = >item.RegionId).Select(grp = >grp.GroupBy(item = >item.BranchId)).Select(grp = >grp.Select(innerg = >innerg.GroupBy(item = >item.UserId))).ToList();
var serializer = JsonConvert.SerializeObject(jsonResponseList, Formatting.Indented);
Root class
public class Root
{
public int UserId { get; set; }
public string FirstName { get; set; }
public int BranchId { get; set; }
public string BranchName { get; set; }
public int RegionId { get; set; }
public string RegionName { get; set; }
}
and the output:
[
[
[
[
{
"UserId": 195,
"FirstName": "Carlton",
"BranchId": 4,
"BranchName": "Test",
"RegionId": 1,
"RegionName": "Admin"
}
],
[
{
"UserId": 223,
"FirstName": "Lorenza",
"BranchId": 4,
"BranchName": "Test",
"RegionId": 1,
"RegionName": "Admin"
}
]
],
[
[
{
"UserId": 163,
"FirstName": "Alice",
"BranchId": 17,
"BranchName": "Ratnapura",
"RegionId": 1,
"RegionName": "Admin"
}
]
]
],
[
[
[
{
"UserId": 264,
"FirstName": "Karen",
"BranchId": 7,
"BranchName": "Peachtree",
"RegionId": 3,
"RegionName": "South Region"
}
],
[
{
"UserId": 266,
"FirstName": "Starla",
"BranchId": 7,
"BranchName": "Peachtree",
"RegionId": 3,
"RegionName": "South Region"
}
]
],
[
[
{
"UserId": 30,
"FirstName": "Jane",
"BranchId": 9,
"BranchName": "Henderson Mill",
"RegionId": 3,
"RegionName": "South Region"
}
]
]
]
]
If these are physically related tables then EF has taken care of it already. Just make sure your lazy loading is ON or you can eager load data as well by using include and then display data as it is. If you want to eager load information then try this query
using(var db = new DBContext){
var result = db.region.include(x => x.branches).theninclude(x => x.users).toList();
}
result will contain all of your data then bind that data into your custom define DTOs or you can directly bind entity models into views.
Its an overview of the code you can have your own implementation.
If there is no physical relations in between tables then use join using linq here is the link you can follow how joins works in linq.
link
Related
var users = new[]
{
new { id = 5, user_id = 3, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 10, },
new { id = 6, user_id = 3, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 11, },
new { id = 7, user_id = 3, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 12, },
new { id = 8, user_id = 5, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 10, },
new { id = 9, user_id = 6, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 11, },
new { id = 10, user_id = 7, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", }, department_id = 12, },
new { id = 11, user_id = 8, permissions = new [] { "apple", "Pineapple", "Strawberry", }, department_id = 10, },
new { id = 12, user_id = 9, permissions = new [] { "apple", "Pineapple", }, department_id = 11, },
new { id = 13, user_id = 10, permissions = new [] { "Gooseberry", "Custard", }, department_id = 12, },
new { id = 20, user_id = 11, permissions = new [] { "Raspberry", }, department_id = 15, },
};
From a list of users and their permissions, I want to find a user's manager.
The manager is a user who has the same department and permissions as the user in question, but they either have more permissions or they work across more departments.
The direct manager is a manager whose departments or permissions are the closest to the user.
for example:
user_id=8 => manager = user_id=5
user_id=5 => manager = user_id=3
user_id=3 has 3 department so he is the manager, user_id=1 has only 1 department.
user_id=11 has no manager.
user_id=5 and user_id=8 has same department but not the same permissions
user_id=10 => manager = user_id=3
user_id=7 is not his manager, they have same department but user_id=7 is missing a permission.
This seems to work:
var users = new[]
{
new { id = 5, user_id = 3, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 10, },
new { id = 6, user_id = 3, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 11, },
new { id = 7, user_id = 3, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 12, },
new { id = 8, user_id = 5, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 10, },
new { id = 9, user_id = 6, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", "Custard", }, department_id = 11, },
new { id = 10, user_id = 7, permissions = new [] { "apple", "Pineapple", "Strawberry", "Gooseberry", }, department_id = 12, },
new { id = 11, user_id = 8, permissions = new [] { "apple", "Pineapple", "Strawberry", }, department_id = 10, },
new { id = 12, user_id = 9, permissions = new [] { "apple", "Pineapple", }, department_id = 11, },
new { id = 13, user_id = 10, permissions = new [] { "Gooseberry", "Custard", }, department_id = 12, },
new { id = 20, user_id = 11, permissions = new [] { "Raspberry", }, department_id = 15, },
};
var userDepartments = users.Select(x => new { x.user_id, x.department_id }).Distinct().ToLookup(x => x.user_id, x => x.department_id);
var query =
from u in users
join m in users on u.department_id equals m.department_id
where u.user_id != m.user_id
where userDepartments[m.user_id].Count() > 1
|| (m.permissions.Except(u.permissions).Any() && !u.permissions.Except(m.permissions).Any())
select new { user = u.user_id, manager = m.user_id };
That gives me:
I'm not sure if you need a single direct linq expression to query all users, but from a first principals I've prepared a fiddle: https://dotnetfiddle.net/LvYRqS
// Get the departments of the passing user
var userPermissions = permissions.Where(x => x.user_id == userId).ToList();
var departments = userPermissions.Select(x => x.department_id).ToList();
// get all the permissions of this user
var usersPermissionValues = userPermissions.SelectMany(x => x.permissions.Split(';')).Select(x => x.Trim()).Where(x => !String.IsNullOrWhiteSpace(x)).Distinct().ToArray();
// managers or higher-ups have the same department(s) or more, and the same permissions or more
var managers = from p in permissions
where p.user_id != userId
group p by p.user_id into u
where departments.All(d => u.Any(x => x.department_id == d))
let mgrPermissions = u.SelectMany(x => x.permissions.Split(';').Select(x => x.Trim()).Where(x => !String.IsNullOrWhiteSpace(x))).Distinct().ToList()
where !usersPermissionValues.Except(mgrPermissions).Any()
select new
{
user_id = u.Key,
permissionCount = mgrPermissions.Count(),
permissions = String.Join(",", mgrPermissions),
missingPermission = usersPermissionValues.Except(mgrPermissions).Count(),
Departments = u.GroupBy(x => x.department_id).Count()
};
// The direct manager is a manager with the lowest count of departments and permissions.
var directManager = managers.OrderBy(x => x.Departments).ThenBy(x => x.permissionCount).Select(x => x.user_id).FirstOrDefault();
return directManager == 0 ? null : directManager;
Given an array of permissions we could query all the users and their direct managers: https://dotnetfiddle.net/E3iItX
IEnumerable<DepartmentUserAccess> permissions = ...
var usersAndDirectManagers =
from p in permissions
group p by p.user_id into user
let userDepartments = user.Select(x => x.department_id).ToList()
let userPermissions = user.SelectMany(x => x.permissions.Split(';').Select(x => x.Trim()).Where(x => !String.IsNullOrWhiteSpace(x))).Distinct().ToList()
select new
{
user_id = user.Key,
departments = userDepartments,
permissions = userPermissions,
manager_id = (from mgr in permissions.Where(x => x.user_id != user.Key).GroupBy(x => x.user_id)
where userDepartments.All(d => mgr.Any(x => x.department_id == d))
let mgrPermissions = mgr.SelectMany(x => x.permissions.Split(';').Select(x => x.Trim()).Where(x => !String.IsNullOrWhiteSpace(x))).Distinct().ToList()
where !userPermissions.Except(mgrPermissions).Any()
orderby mgr.Select(x => x.department_id).Count()
orderby mgrPermissions.Count()
select mgr.Key).Cast<int?>().DefaultIfEmpty((int?)null).First()
};
If you had to query this only in a specific report, then I guess it would work. The problem is that the number of permissions or even permissions itself not a very good metric for most software platforms, for this to work you are expecting all possible permissions to be expanded out for each user which is troublesome for role-based security models.
A declarative approach will make the data processing more efficient if you have to do this type of query a lot. If each department has a specific supervisor or manager, then put the supervisor FK on the department table. Otherwise user's supervisor could be defined as an FK on the user table.
Some systems will group the users into teams who have a single supervisor, this model makes it easy to swap out the supervisor whilst still retaining the rest of the team, the team can have a department FK enabling multiple teams per department, or you might even create a M:N relationship between teams and departments if you need to.
A declarative structure would also help to query the reverse, show me the users for each manager, or to build a hierarchical tree showing the CEO at the top, showing for each management level who their direct reports are. You can do it with the current structure, but it's not pretty LINQ or SQL.
I have two arrayList here here:
List<ArrayList1> data = new List<ArrayList1>() {
{ id = 1, name = "John Doe", age = 20 },
{ id = 2, name = "Mae Doe", age = 17 },
{ id = 3, name = "Mark Smith", age = 35 },
{ id = 4, name = "Selena Smith", age = 15 },
{ id = 5, name = "Shane Doe", age = 26 },
{ id = 6, name = "Will Smith", age = 45 }
};
List<ArrayList2> data = new List<ArrayList2>() {
{ id = 1, address = "Singapore", phone_number = "123", store_name = "ABC" },
{ id = 4, address = "Japan", phone_number = "456", store_name = "DEF" },
{ id = 5, address = "Korea", phone_number = "789", store_name = "GHI" }
};
I want to join them, kind of left join in mysql so the result will be like this
List<ArrayListResult> data = new List<ArrayListResult>() {
{ id = 1, name = "John Doe", age = 20, address = "Singapore", phone_number = "123", store_name = "ABC" },
{ id = 2, name = "Mae Doe", age = 17 },
{ id = 3, name = "Mark Smith", age = 35 },
{ id = 4, name = "Selena Smith", age = 15, address = "Japan", phone_number = "456", store_name = "DEF" },
{ id = 5, name = "Shane Doe", age = 26, address = "Korea", phone_number = "789", store_name = "GHI" },
{ id = 6, name = "Will Smith", age = 45 }
};
The address, phone_number, store_name will be merged to List based on the matched id.
Is there easy way of merging 2 arrayList in c# based on matched id? Please help. Thanks!
You're looking for this:
result =
(
from d1 in data1
join d2 in data2 on d1.id equals d2.id into gds
from gd in gds.DefaultIfEmpty()
select new ArrayListResult()
{
id = d1.id,
name = d1.name,
age = d1.age,
address = gd?.address,
phone_number = gd?.phone_number,
store_name = gd?.store_name,
}
).ToList();
That gives me:
so I'm using couchbase queue to Enqueue my beacon information. I'm trying to use n1ql query for my get method and I'm having trouble getting all the information. I realized I'm only getting the first beacon entry because result.Rows returns one element, an array of BeaconInfoN1ql. I wanted to iterate through that array and add each to a list.
try {
var cluster = new Cluster(new ClientConfiguration());
using (var bucket = cluster.OpenBucket("BeaconInfoN1ql"))
{
string query = "SELECT * FROM `BeaconInfoN1ql`";
var queryRequest = new QueryRequest(query);
var result = bucket.Query<dynamic>(queryRequest);
foreach (var row in result.Rows)
{
int i = 0;
var beacon = new Beacon()
{
SerialNumber = row.BeaconInfoN1ql[i].serialNumber,
ReceivedDate = Convert.ToDateTime(row.BeaconInfoN1ql[i].receivedDate),
ReceiverId = row.BeaconInfoN1ql[i].receiverId,
Distance = Convert.ToDouble(row.BeaconInfoN1ql[i].distance),
Rssi = Convert.ToInt32(row.BeaconInfoN1ql[i].rssi),
NewDistance = Convert.ToDouble(row.BeaconInfoN1ql[i].newDistance),
DistanceTesting = Convert.ToDouble(row.BeaconInfoN1ql[i].distanceTesting),
};
i++;
_beaconsList.Add(beacon);
}
}
return _beaconsList;
my result.Rows looks like this
result.Rows=
{{
"BeaconInfoN1ql": [
{
"distance": 2.2705747109792007,
"distanceTesting": 22,
"newDistance": 22,
"receivedDate": "0001-01-01T00:00:00",
"receiverId": "42008780c4b9b329",
"rssi": -73,
"serialNumber": "888"
},
{
"distance": 2.2705747109792007,
"distanceTesting": 22,
"newDistance": 22,
"receivedDate": "0001-01-01T00:00:00",
"receiverId": "42008780c4b9b329",
"rssi": -73,
"serialNumber": "888"
},
{
"distance": 2.2705747109792007,
"distanceTesting": 22,
"newDistance": 22,
"receivedDate": "0001-01-01T00:00:00",
"receiverId": "42008780c4b9b329",
"rssi": -73,
"serialNumber": "888"
},
{
"distance": 2.2705747109792007,
"distanceTesting": 22,
"newDistance": 22,
"receivedDate": "0001-01-01T00:00:00",
"receiverId": "42008780c4b9b329",
"rssi": -73,
"serialNumber": "888"
},
]
}}
I'm not sure about how to make the second foreach/for loop to iterate through all the keys.
For iterating JSON, I like to use dynamics. Here's an example:
var result = new Result()
{
Rows = #"{
'BeaconInfoN1ql': [
{
'distance': 2.2705747109792007,
'distanceTesting': 22,
'newDistance': 22,
'receivedDate': '0001-01-01T00:00:00',
'receiverId': '42008780c4b9b329',
'rssi': -73,
'serialNumber': '888'
}
]
}" //other entries omitted for brevity
};
dynamic parsedRows = JsonConvert.DeserializeObject(result.Rows);
foreach (var entry in parsedRows.BeaconInfoN1ql)
Debug.Write(entry.distance);
NOTE: I got rid of the double curly braces from your output in my example.
My first JSON is as follows
[{
"UserId": 4,
"FirstName": "rupesh",
"LastName": "Abc",
"Email": "abc#gmail.com",
"Gender": "Male"
}]
My Second JSON is as follows
[{
"AccountId": 2,
"AccountName": "rupeshinfo",
"AccountDomain": null,
"RoleId": 1,
"UserId": 4
}, {
"AccountId": 3,
"AccountName": "Rameshinfo",
"AccountDomain": null,
"RoleId": 2,
"UserId": 4
}]
the result must be
{
"UserDetails": [{
"UserId": 4,
"FirstName": "rupesh",
"LastName": "Abc",
"Email": "abc#gmail.com",
"Gender": "Male"
}],
"AccountDetails": [{
"AccountId": 2,
"AccountName": "rupeshinfo",
"AccountDomain": null,
"RoleId": 1,
"UserId": 4
}, {
"AccountId": 3,
"AccountName": "Rameshinfo",
"AccountDomain": null,
"RoleId": 2,
"UserId": 4
}]
}
If you don't want to mess with string inserts you can go with (and I recommend so) using dynamic objects:
var javaScriptSerializer = new JavaScriptSerializer();
var userDetails = javaScriptSerializer.DeserializeObject(json1);
var accountDetails = javaScriptSerializer.DeserializeObject(json2);
var resultJson = javaScriptSerializer.Serialize(new {UserDetails = userDetails, AccountDetails = accountDetails});
You can deserialize them into two objects, create new anonimous type of these objects, and serialize them into the end one json:
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
var result = jsonSerializer.Serialize(new
{
UserDetails = jsonSerializer.DeserializeObject(#"[{
'UserId': 4,
'FirstName': 'rupesh',
'LastName': 'Abc',
'Email': 'abc#gmail.com',
'Gender': 'Male'
}]"),
AccountDetails = jsonSerializer.DeserializeObject(#"[{
'AccountId': 2,
'AccountName': 'rupeshinfo',
'AccountDomain': null,
'RoleId': 1,
'UserId': 4
}, {
'AccountId': 3,
'AccountName': 'Rameshinfo',
'AccountDomain': null,
'RoleId': 2,
'UserId': 4
}]")
});
Try this
var jsonStr ='{"UserDetails":[{"UserId": 4,"FirstName": "rupesh","LastName": "Abc","Email": "abc#gmail.com","Gender": "Male"}]}'
var obj = JSON.parse(jsonStr);
obj['AccountDetails'].push({"AccountId": 2,"AccountName": "rupeshinfo","AccountDomain": null,"RoleId": 1,"UserId": 4}, {"AccountId": 3,"AccountName": "Rameshinfo","AccountDomain": null,"RoleId": 2,"UserId": 4});
jsonStr = JSON.stringify(obj);
I'm in process of trying to learn JWT and ouath. I have came across form of JWT which would help me in development of my authorization server.
The format I came across is following :
{
iat: 1416929061,
jti: "802057ff9b5b4eb7fbb8856b6eb2cc5b",
scopes: {
users: {
actions: ['read', 'create']
},
users_app_metadata: {
actions: ['read', 'create']
}
}
}
However since in adding claims we can only add simple string how something like this can be achieved ?
The only way I have seen till now was to use JSON.serialization - coming from https://stackoverflow.com/a/27279400/2476347
new Claim(someClass,JsonConvert.SerializeObject(result)
any guidelines would be much appreciated! Thanks!
Code used for testing
Class I would like to use in JWT
public class MyTes
{
public string area { get; set; }
public List<string> areapermissions { get; set; }
}
And then I use the following code for token generation
var identity = new ClaimsIdentity("JWT");
var cos = new List<string>();
cos.Add("aaa");
cos.Add("bbb");
MyTes vario = new MyTes()
{
area = "someregion",
areapermissions = cos
};
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Role, "Manager"));
identity.AddClaim(new Claim(ClaimTypes.Role, "Supervisor"));
identity.AddClaim(new Claim("scope", "xyz1"));
identity.AddClaim(new Claim("scope", "xyz2"));
identity.AddClaim(new Claim("scope", "xyz3"));
identity.AddClaim(new Claim("APIs", JsonConvert.SerializeObject(cos)));
identity.AddClaim(new Claim("APIs2", JsonConvert.SerializeObject(vario)));
This gives no errors and when I decode the ticket I get now :
{
"unique_name": "Rafski",
"sub": "Rafski",
"role": [
"Manager",
"Supervisor"
],
"scope": [
"xyz1",
"xyz2",
"xyz3"
],
"APIs": "[\"aaa\",\"bbb\"]",
"APIs2": "{\"area\":\"someregion\",\"areapermissions\":[\"aaa\",\"bbb\"]}",
"iss": "http://kurwa.mac",
"aud": "7aaa70ed8f0b4807a01596e2abfbd44d",
"exp": 1429351056,
"nbf": 1429349256
}
Here's how to create a JWT token with complex JSON claims using .Net.
Use Nuget to get the Library: System.IdentityModel.Tokens.Jwt
Then use the following code to create a JWT token.
var keybytes = Convert.FromBase64String(YOUR_CLIENT_SECRET);
var signingCredentials = new SigningCredentials(
new InMemorySymmetricSecurityKey(keybytes),
SecurityAlgorithms.HmacSha256Signature,
SecurityAlgorithms.Sha256Digest);
var nbf = DateTime.UtcNow.AddSeconds(-1);
var exp = DateTime.UtcNow.AddSeconds(120);
var payload = new JwtPayload(null, "", new List<Claim>(), nbf, exp);
var users = new Dictionary<string, object>();
users.Add("actions", new List<string>() { "read", "create" });
var scopes = new Dictionary<string, object>();
scopes.Add("users", users);
payload.Add("scopes", scopes);
var jwtToken = new JwtSecurityToken(new JwtHeader(signingCredentials), payload);
var jwtTokenHandler = new JwtSecurityTokenHandler();
return jwtTokenHandler.WriteToken(jwtToken);
Which would produce a token such as
{
"typ": "JWT",
"alg": "HS256"
}
{
"exp": 1433254394,
"nbf": 1433254273,
"scopes": {
"users": {
"actions": [
"read", "create"
]
}
}
}
This has been never an issue these days. It can be solved using the
Payload section of the token.
**using System.IdentityModel.Tokens.Jwt;** //Vesrion 5.5.0
Sample code
public static string Generate()
{
IList<User> users = new List<User> {
new User { Id = 1, Name = "User One" },
new User { Id = 2, Name = "User Two" },
new User { Id = 3, Name = "User Three" }
};
IList<Company> companies = new List<Company>
{
new Company{ Id = 1, Code = "C01", Name = "Company I", Users = users },
new Company{ Id = 2, Code = "C03", Name = "Company II", Users = null },
new Company{ Id = 3, Code = "C03", Name = "Company III", Users = users }
};
IList<Branch> branches = new List<Branch>
{
new Branch{Id = 1, CompanyId = 1, Code="B01", Name = "Branch 1.1"},
new Branch{Id = 2, CompanyId = 1, Code="B02", Name = "Branch 1.2"},
new Branch{Id = 3, CompanyId = 1, Code="B03", Name = "Branch 1.3"},
new Branch{Id = 4, CompanyId = 2, Code="B04", Name = "Branch 2.1"},
new Branch{Id = 5, CompanyId = 2, Code="B05", Name = "Branch 2.2"},
};
var payload = new JwtPayload {
{ "companies", companies },
{ "branches", branches }
};
string key = "eyJjb21wYW5pZXMiOlt7IklkIjoxLCJDb2RlIjoiQzAxIiwiTmFtZSI6IkNvbXBhbnkgSSIsIkJyYW5jaGVzIjpudWxsLCJVc2VycyI6W3siSWQiOjEsIk5hbWUiOiJV";
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var header = new JwtHeader(credentials);
var secToken = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
var tokenString = handler.WriteToken(secToken);
Console.WriteLine(secToken);
Console.WriteLine(tokenString);
return tokenString;
}
Output
{
"companies": [
{
"Id": 1,
"Code": "C01",
"Name": "Company I",
"Branches": null,
"Users": [
{
"Id": 1,
"Name": "User One"
},
{
"Id": 2,
"Name": "User Two"
},
{
"Id": 3,
"Name": "User Three"
}
]
},
{
"Id": 2,
"Code": "C03",
"Name": "Company II",
"Branches": null,
"Users": null
},
{
"Id": 3,
"Code": "C03",
"Name": "Company III",
"Branches": null,
"Users": [
{
"Id": 1,
"Name": "User One"
},
{
"Id": 2,
"Name": "User Two"
},
{
"Id": 3,
"Name": "User Three"
}
]
}
],
"branches": [
{
"Id": 1,
"CompanyId": 1,
"Code": "B01",
"Name": "Branch 1.1"
},
{
"Id": 2,
"CompanyId": 1,
"Code": "B02",
"Name": "Branch 1.2"
},
{
"Id": 3,
"CompanyId": 1,
"Code": "B03",
"Name": "Branch 1.3"
},
{
"Id": 4,
"CompanyId": 2,
"Code": "B04",
"Name": "Branch 2.1"
},
{
"Id": 5,
"CompanyId": 2,
"Code": "B05",
"Name": "Branch 2.2"
}
]
}
Token
eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJjb21wYW5pZXMiOlt7IklkIjoxLCJDb2RlIjoiQzAxIiwiTmFtZSI6IkNvbXBhbnkgSSIsIkJyYW5jaGVzIjpudWxsLCJVc2VycyI6W3siSWQiOjEsIk5hbWUiOiJVc2VyIE9uZSJ9LHsiSWQiOjIsIk5hbWUiOiJVc2VyIFR3byJ9LHsiSWQiOjMsIk5hbWUiOiJVc2VyIFRocmVlIn1dfSx7IklkIjoyLCJDb2RlIjoiQzAzIiwiTmFtZSI6IkNvbXBhbnkgSUkiLCJCcmFuY2hlcyI6bnVsbCwiVXNlcnMiOm51bGx9LHsiSWQiOjMsIkNvZGUiOiJDMDMiLCJOYW1lIjoiQ29tcGFueSBJSUkiLCJCcmFuY2hlcyI6bnVsbCwiVXNlcnMiOlt7IklkIjoxLCJOYW1lIjoiVXNlciBPbmUifSx7IklkIjoyLCJOYW1lIjoiVXNlciBUd28ifSx7IklkIjozLCJOYW1lIjoiVXNlciBUaHJlZSJ9XX1dLCJicmFuY2hlcyI6W3siSWQiOjEsIkNvbXBhbnlJZCI6MSwiQ29kZSI6IkIwMSIsIk5hbWUiOiJCcmFuY2ggMS4xIn0seyJJZCI6MiwiQ29tcGFueUlkIjoxLCJDb2RlIjoiQjAyIiwiTmFtZSI6IkJyYW5jaCAxLjIifSx7IklkIjozLCJDb21wYW55SWQiOjEsIkNvZGUiOiJCMDMiLCJOYW1lIjoiQnJhbmNoIDEuMyJ9LHsiSWQiOjQsIkNvbXBhbnlJZCI6MiwiQ29kZSI6IkIwNCIsIk5hbWUiOiJCcmFuY2ggMi4xIn0seyJJZCI6NSwiQ29tcGFueUlkIjoyLCJDb2RlIjoiQjA1IiwiTmFtZSI6IkJyYW5jaCAyLjIifV19.ysjwBa3YeYNmVB0fVEh95wL0zt8Krb-T4VRpWKWIfbU
So the key to this problem is understanding :) Firs what should be noted is the following escape characters .
That basically made me understand that all I need is proper serialization/deserialization of custom array objects.
So I have created the following as base of each scope
Dictionary<string, List<string>> xx3 = new Dictionary<string, List<string>>()
{
{
"s3",new List<string>()
{
"access1" , "access2"
}
}
};
Then simply serialized this object and added as claim
var cos3 = JsonConvert.SerializeObject(xx3, Formatting.Indented);
identity.AddClaim(new Claim("scopes", cos1));
Now what has left as challenge was appropriate authorization on my resources.So I have added customized AuthorizationFilterAttribute
Within there I have deserialized claims using code from here
For those who would be looking for some more of code this is snippet from my custom filter:
// Check if we have scopes
var AllScopes = principal.Claims.Where(p => p.Type == "scopes");
// Check if we have desired scope
foreach (var singlescope in AllScopes)
{
Dictionary<string, List<string>> userscopes = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(singlescope.Value);
if (userscopes.Single(kvp => kvp.Key == ScopeName).Value.Contains(ScopeAccess))
{
//User is Authorized, complete execution
return Task.FromResult<object>(null);
}
}
I hope this will help someone!
Here is how I created my complex token:
var securityKey = new InMemorySymmetricSecurityKey(Encoding.Default.GetBytes("401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1"));
var signingCredentials = new SigningCredentials(securityKey,
SecurityAlgorithms.HmacSha256Signature,
SecurityAlgorithms.Sha256Digest);
var header = new JwtHeader(signingCredentials);
var payload = new JwtPayload();
payload.AddClaims(claims);
payload.Add("tags", _tags.ToArray()); // this guy accepts object!
var token = new JwtSecurityToken(header, payload);
var tokenString = securityTokenHandler.WriteToken(token);