Skip to content

Commit c2711e6

Browse files
committed
SignalR ile JWT entegrasyonu yapıldı.
1 parent 47e8efe commit c2711e6

File tree

8 files changed

+160
-116
lines changed

8 files changed

+160
-116
lines changed
Binary file not shown.

ChatSample/.vs/ChatSample/v16/.suo

3.5 KB
Binary file not shown.
Binary file not shown.

ChatSample/ChatSample/Hubs/ChatHub.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
using Microsoft.AspNetCore.SignalR;
1+
using Microsoft.AspNetCore.Authentication.JwtBearer;
2+
using Microsoft.AspNetCore.Authorization;
3+
using Microsoft.AspNetCore.SignalR;
24

35
namespace ChatSample.Hubs
46
{
7+
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
58
public class ChatHub : Hub
69
{
710
public void Send(string name, string message)

ChatSample/ChatSample/Startup.cs

Lines changed: 53 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System.Text;
2-
using System.Threading.Tasks;
3-
using ChatSample.Helpers;
1+
using ChatSample.Helpers;
42
using ChatSample.Hubs;
53
using ChatSample.IServices;
64
using ChatSample.Services;
@@ -10,44 +8,55 @@
108
using Microsoft.Extensions.Configuration;
119
using Microsoft.Extensions.DependencyInjection;
1210
using Microsoft.IdentityModel.Tokens;
11+
using System.Text;
12+
using System.Threading.Tasks;
1313

14-
namespace ChatSample {
15-
public class Startup {
16-
public Startup (IConfiguration configuration) => Configuration = configuration;
14+
namespace ChatSample
15+
{
16+
public class Startup
17+
{
18+
public Startup(IConfiguration configuration) => Configuration = configuration;
1719
public IConfiguration Configuration { get; }
18-
public void ConfigureServices (IServiceCollection services) {
19-
services.AddCors ();
20-
services.AddControllers ();
21-
services.AddSignalR ();
20+
public void ConfigureServices(IServiceCollection services)
21+
{
22+
services.AddCors();
23+
services.AddControllers();
24+
services.AddSignalR();
2225

2326
// configure strongly typed settings objects
24-
var appSettingsSection = Configuration.GetSection ("AppSettings");
25-
services.Configure<AppSettings> (appSettingsSection);
27+
var appSettingsSection = Configuration.GetSection("AppSettings");
28+
services.Configure<AppSettings>(appSettingsSection);
2629

2730
// configure jwt authentication
28-
var appSettings = appSettingsSection.Get<AppSettings> ();
29-
var key = Encoding.ASCII.GetBytes (appSettings.Secret);
30-
services.AddAuthentication (x => {
31-
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
32-
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
33-
})
34-
.AddJwtBearer (x => {
31+
var appSettings = appSettingsSection.Get<AppSettings>();
32+
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
33+
services.AddAuthentication(x =>
34+
{
35+
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
36+
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
37+
})
38+
.AddJwtBearer(x =>
39+
{
3540
x.RequireHttpsMetadata = false;
3641
x.SaveToken = true;
37-
x.TokenValidationParameters = new TokenValidationParameters {
42+
x.TokenValidationParameters = new TokenValidationParameters
43+
{
3844
ValidateIssuerSigningKey = true,
39-
IssuerSigningKey = new SymmetricSecurityKey (key),
45+
IssuerSigningKey = new SymmetricSecurityKey(key),
4046
ValidateIssuer = false,
4147
ValidateAudience = false
4248
};
43-
x.Events = new JwtBearerEvents {
44-
OnMessageReceived = context => {
49+
x.Events = new JwtBearerEvents
50+
{
51+
OnMessageReceived = context =>
52+
{
4553
var accessToken = context.Request.Query["access_token"];
4654

4755
// If the request is for our hub...
4856
var path = context.HttpContext.Request.Path;
49-
if (!string.IsNullOrEmpty (accessToken) &&
50-
(path.StartsWithSegments ("/hubs/chat"))) {
57+
if (!string.IsNullOrEmpty(accessToken) &&
58+
(path.StartsWithSegments("/hubs/chat")))
59+
{
5160
// Read the token out of the query string
5261
context.Token = accessToken;
5362
}
@@ -57,32 +66,35 @@ public void ConfigureServices (IServiceCollection services) {
5766
});
5867

5968
// configure DI for application services
60-
services.AddScoped<IUserService, UserService> ();
69+
services.AddScoped<IUserService, UserService>();
6170
}
6271

6372
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
6473

6574
[System.Obsolete]
66-
public void Configure (IApplicationBuilder app, IHostingEnvironment env) {
67-
app.UseRouting ();
68-
if (env.IsDevelopment ()) {
69-
app.UseDeveloperExceptionPage ();
75+
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
76+
{
77+
app.UseRouting();
78+
if (env.IsDevelopment())
79+
{
80+
app.UseDeveloperExceptionPage();
7081
}
7182

72-
app.UseFileServer ();
83+
app.UseFileServer();
7384

74-
app.UseCors (builder => builder
75-
.AllowAnyHeader ()
76-
.AllowAnyMethod ()
77-
.SetIsOriginAllowed ((host) => true)
78-
.AllowCredentials ()
85+
app.UseCors(builder => builder
86+
.AllowAnyHeader()
87+
.AllowAnyMethod()
88+
.SetIsOriginAllowed((host) => true)
89+
.AllowCredentials()
7990
);
8091

81-
app.UseAuthentication ();
82-
app.UseAuthorization ();
83-
app.UseEndpoints (endpoints => {
84-
endpoints.MapControllers ();
85-
endpoints.MapHub<ChatHub> ("/chat");
92+
app.UseAuthentication();
93+
app.UseAuthorization();
94+
app.UseEndpoints(endpoints =>
95+
{
96+
endpoints.MapControllers();
97+
endpoints.MapHub<ChatHub>("/hubs/chat");
8698
});
8799

88100
}

react-chat/src/HomePage/HomePage.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import React from "react";
2-
import { HubConnectionBuilder } from "@aspnet/signalr";
2+
import { HubConnectionBuilder, LogLevel } from "@aspnet/signalr";
33

44
import { authenticationService } from "../_services";
55

66
class HomePage extends React.Component {
77
constructor(props) {
88
super(props);
9+
console.log(authenticationService.currentUserValue);
910

1011
this.state = {
1112
currentUser: authenticationService.currentUserValue,
1213
connection: new HubConnectionBuilder()
13-
.withUrl("http://localhost:50704/chat")
14+
.withUrl("http://localhost:50704/hubs/chat", {
15+
accessTokenFactory:()=> authenticationService.currentUserValue.token
16+
})
17+
.configureLogging(LogLevel.Information)
1418
.build(),
1519
messages: [],
1620
message: "",
@@ -54,6 +58,7 @@ class HomePage extends React.Component {
5458
};
5559
render() {
5660
const currentUser = this.state.currentUser;
61+
5762
const listItems = this.state.messages.map((item, key) => (
5863
<li key={key}>
5964
<strong>{item.name} : </strong>
Lines changed: 96 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,105 @@
1-
import React from 'react';
2-
import { Formik, Field, Form, ErrorMessage } from 'formik';
3-
import * as Yup from 'yup';
1+
import React from "react";
2+
import { Formik, Field, Form, ErrorMessage } from "formik";
3+
import * as Yup from "yup";
44

5-
import { authenticationService } from '../_services';
5+
import { authenticationService } from "../_services";
66

77
class LoginPage extends React.Component {
8-
constructor(props) {
9-
super(props);
8+
constructor(props) {
9+
super(props);
1010

11-
// redirect to home if already logged in
12-
if (authenticationService.currentUserValue) {
13-
this.props.history.push('/');
14-
}
11+
// redirect to home if already logged in
12+
if (authenticationService.currentUserValue) {
13+
this.props.history.push("/");
1514
}
15+
}
1616

17-
render() {
18-
return (
19-
<div>
20-
<div className="alert alert-info">
21-
Username: test<br />
22-
Password: test
23-
</div>
24-
<h2>Login</h2>
25-
<Formik
26-
initialValues={{
27-
username: '',
28-
password: ''
29-
}}
30-
validationSchema={Yup.object().shape({
31-
username: Yup.string().required('Username is required'),
32-
password: Yup.string().required('Password is required')
33-
})}
34-
onSubmit={({ username, password }, { setStatus, setSubmitting }) => {
35-
setStatus();
36-
authenticationService.login(username, password)
37-
.then(
38-
user => {
39-
const { from } = this.props.location.state || { from: { pathname: "/" } };
40-
this.props.history.push(from);
41-
},
42-
error => {
43-
setSubmitting(false);
44-
setStatus(error);
45-
}
46-
);
47-
}}
48-
render={({ errors, status, touched, isSubmitting }) => (
49-
<Form>
50-
<div className="form-group">
51-
<label htmlFor="username">Username</label>
52-
<Field name="username" type="text" className={'form-control' + (errors.username && touched.username ? ' is-invalid' : '')} />
53-
<ErrorMessage name="username" component="div" className="invalid-feedback" />
54-
</div>
55-
<div className="form-group">
56-
<label htmlFor="password">Password</label>
57-
<Field name="password" type="password" className={'form-control' + (errors.password && touched.password ? ' is-invalid' : '')} />
58-
<ErrorMessage name="password" component="div" className="invalid-feedback" />
59-
</div>
60-
<div className="form-group">
61-
<button type="submit" className="btn btn-primary" disabled={isSubmitting}>Login</button>
62-
{isSubmitting &&
63-
<img src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
64-
}
65-
</div>
66-
{status &&
67-
<div className={'alert alert-danger'}>{status}</div>
68-
}
69-
</Form>
70-
)}
17+
render() {
18+
return (
19+
<div>
20+
<div className="alert alert-info">
21+
Username: test
22+
<br />
23+
Password: test
24+
</div>
25+
<h2>Login</h2>
26+
<Formik
27+
initialValues={{
28+
username: "",
29+
password: ""
30+
}}
31+
validationSchema={Yup.object().shape({
32+
username: Yup.string().required("Username is required"),
33+
password: Yup.string().required("Password is required")
34+
})}
35+
onSubmit={({ username, password }, { setStatus, setSubmitting }) => {
36+
setStatus();
37+
authenticationService.login(username, password).then(
38+
user => {
39+
const { from } = this.props.location.state || {
40+
from: { pathname: "/" }
41+
};
42+
this.props.history.push(from);
43+
},
44+
error => {
45+
setSubmitting(false);
46+
setStatus(error);
47+
}
48+
);
49+
}}
50+
render={({ errors, status, touched, isSubmitting }) => (
51+
<Form>
52+
<div className="form-group">
53+
<label htmlFor="username">Username</label>
54+
<Field
55+
name="username"
56+
type="text"
57+
className={
58+
"form-control" +
59+
(errors.username && touched.username ? " is-invalid" : "")
60+
}
7161
/>
72-
</div>
73-
)
74-
}
62+
<ErrorMessage
63+
name="username"
64+
component="div"
65+
className="invalid-feedback"
66+
/>
67+
</div>
68+
<div className="form-group">
69+
<label htmlFor="password">Password</label>
70+
<Field
71+
name="password"
72+
type="password"
73+
className={
74+
"form-control" +
75+
(errors.password && touched.password ? " is-invalid" : "")
76+
}
77+
/>
78+
<ErrorMessage
79+
name="password"
80+
component="div"
81+
className="invalid-feedback"
82+
/>
83+
</div>
84+
<div className="form-group">
85+
<button
86+
type="submit"
87+
className="btn btn-primary"
88+
disabled={isSubmitting}
89+
>
90+
Login
91+
</button>
92+
{isSubmitting && (
93+
<img src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
94+
)}
95+
</div>
96+
{status && <div className={"alert alert-danger"}>{status}</div>}
97+
</Form>
98+
)}
99+
/>
100+
</div>
101+
);
102+
}
75103
}
76104

77-
export { LoginPage };
105+
export { LoginPage };

react-chat/src/index.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,4 @@ import ReactDOM from "react-dom";
33

44
import { App } from "./App";
55

6-
// setup fake backend
7-
import { configureFakeBackend } from "./_helpers";
8-
configureFakeBackend();
9-
106
ReactDOM.render(<App />, document.getElementById("root"));

0 commit comments

Comments
 (0)