I'm building a project in Django, and I'm using django-allauth for the social authentication, but I had already set up an authentication system of my own.
Now, as I said, I just wanted to use django-allauth for the social authentication, but NOT for the classic authentication, since - I have tried it - it's authentication system collides with my own.
I've tried overriding the form by creating a FormView like the following:
class LoginUser(FormView):
template_name = 'account/login.html'
form_class = MyLoginForm
That calls this form:
class MyLoginForm(forms.ModelForm):
"""
A form that login a user.
"""
email = forms.EmailField(label='', required=True, widget = forms.TextInput(
attrs = {
'placeholder': 'DIOCAAAAA',
'class': 'form-control',
'id': 'login-email'
}
))
password1 = forms.CharField(label='', required=True, widget=forms.PasswordInput(attrs = {
'placeholder': 'Password',
'class': 'form-control',
'id': 'login-password',
'data-parsley-trigger': 'focusout'
}
))
class Meta:
model = CustomUser
fields = ('email',)
And I've added this in the urls:
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^accounts/', include('allauth.urls')),
**url(r'^accounts/login/$', views.LoginUser.as_view()),**
[...]
)
But I get this error:
TypeError at /accounts/login/
init() got an unexpected keyword argument 'request'
Am I proceeding in the right direction, or should I try something else?
Try to change your Url to be different location,I think your url conflict with allauth url,because allauth has already had this
url(r'^accounts/login/$')
Related
I am working on a flutter application, and I want to implement social login (Google and Facebook).
My API is implemented with Laravel and uses Laravel-socialite to authenticate users, there is the backend, web frontend (using VueJs) and now I am working on the mobile application using flutter.
The web application is working good (using the vue-social-auth package).
What I have done till now:
Used flutter_google_sign_in to handle authentication on the flutter app.
Did configure the package and I can successfully get user info through that package.
Problem I am facing:
What I don't seem to get working is to send the user that just logged in to the backend in order to provide an in-app user experience.
This is what the vue-social-auth package provides and what I send to the backend, which is working fine:
{code: "4/0AY0e-g442SMxdtLb_MVdQ63u1ydp48bbCRQco5Azoyf3y1rvYybDabyZGOvwAs7ZFJDQHA", scope: "email+profile+openid+https://www.googleapis.com/au…le+https://www.googleapis.com/auth/userinfo.email", authuser: "0", prompt: "consent"}
And this is what flutter_google_sign_in gives (aside of the user profile data:
idToken: "",
accessToken: "",
serverAuthCode: "",
serverAuthCode is always null.
How can I make it so that, using the same API logic, log-in users on flutter through social accounts?
Thank you.
Apparently, google sign in doesn't work on flutter except with Firebase/some cloud API backend service. I was using a local Laravel API for user auth so adding google sign in functionality requires setting up a firebase account/profile, downloading and adding the googleservices.json file to flutter project as explained in google_sign_in package installation manual. You also need to import firebase-auth package
Flutter Code (I use flutter modular pattern but same applies with Bloc/Provider if you get the idea as explained by Hamza Mogni above)
import 'package:google_sign_in/google_sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart';
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<LoginResponseModel> googleLoginResponse() async {
String url = env['API_BASE_URL'] + '/api/auth/google';
//click on google sign in. Get accessToken from google through googlesignin
plugin.
//Send accessToken to socialite in backend to request/create user data
GoogleSignInAccount googleSignInAccount = await _googleSignIn.signIn();
if (googleSignInAccount == null) {
print('Google Signin ERROR! googleAccount: null!');
return null;
}
GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
//this is user access token from google that is retrieved with the plugin
print("User Access Token: ${googleSignInAuthentication.accessToken}");
String accessToken = googleSignInAuthentication.accessToken;
//make http request to the laravel backend
final response =
await http.post(
url,
body: json.encode({"token": accessToken}),
headers: {"Content-Type": "application/json"});
if (response.statusCode == 200 || response.statusCode == 422) {
return LoginResponseModel.fromJson(
json.decode(response.body), // {'message':'Google signin successful'}
);
} else {
throw Exception('Failed to load data!');
}
}
For Logout function, you need to signout of both firebase and google account instance or you will always be logged in by the first known/used google account in subsequent login attempts.
Future<LogoutResponseModel> logout() async {
try {
await _auth.signOut();
await _googleSignIn.disconnect();
} catch (e) {
print('Failed to sign out ' + e.toString());
}
//api route to destroy sanctum token. santum token is added as authorization header
var url = env['API_BASE_URL'] + "/api/logout";
final response =
await http.post(Uri.tryParse(url), headers: {'Bearer ' $sanctumtoken});
if (response.statusCode == 200 || response.statusCode == 422) {
return LogoutResponseModel.fromJson(
json.decode(response.body),
);
} else {
throw Exception('Failed to load data!');
}
}
Laravel Code (route to controller method is api/auth/google, method expects to receive google access token from flutter app)
public function requestTokenGoogle(Request $request) {
// Getting the user from socialite using token from google
$user = Socialite::driver('google')->stateless()->userFromToken($request->token);
// Getting or creating user from db
$userFromDb = User::firstOrCreate(
['email' => $user->getEmail()],
[
'email_verified_at' => now(),
'first_name' => $user->offsetGet('given_name'),
'last_name' => $user->offsetGet('family_name'),
'avatar' => $user->getAvatar(),
]
);
// Returning response
$token = $userFromDb->createToken('Laravel Sanctum Client')->plainTextToken;
$response = ['token' => $token, 'message' => 'Google Login/Signup Successful'];
return response($response, 200);
}
I have solved it, after some digging I found out Laravel-Socialite has the functionality to log in users using their token built-in:
Quoting Socialite documentation:
If you already have a valid access token for a user, you can retrieve their details using Socialite's userFromToken method.
I'm trying to create an ASP.Net Core app which contains both MVC and API controllers in single project. For authenticating I use IdentityServer4.
Currently when the user is not authorized for a request he is always redirected to Account/AccessDenied path regardless of authentication scheme. But I want to keep this behavior only for MVC controllers. For API requests I just want to return 403 status code.
Configuration:
services
.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(ApiResourceProvider.GetAllResources())
.AddAspNetIdentity<ApplicationUser>()
.AddInMemoryClients(clientStore.AllClients);
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = tokenAuth.Issuer,
ValidateAudience = true,
ValidAudience = tokenAuth.Audience,
ValidateLifetime = true,
IssuerSigningKey = tokenAuth.SecurityKey,
ValidateIssuerSigningKey = true
};
});
How can I achieve that?
If you're using cookies you can override the AccessDeniedPath like the following
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies", (options) =>
{
options.AccessDeniedPath = "/Authorization/AccessDenied";
})
Actually it was quite simple but not obvious: it's needed to explicitly specify authentication scheme in [Authorize] attribute.
I tried to specify [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] on a controller level but it seems that setting [Authorize(Roles = RoleHelper.MobileWorker)] on the action level overrides the auth schema.
So I created a custom attribute which is derived from Authorize but with properly set auth scheme.
I am having problem bypassing UI login. My web application doesn't use API to authenticate users. There are no endpoints like /login. index.php will just open the login page and submit the form to login.
The application authenticate the user by
auth($_REQUEST['username'], $_REQUEST['password_tx']);
This is what cypress printed after UI login submit.
I have no idea how to move on from here.
// This doesn't work. The application doesn't get the user details from the body. It is in the submitted form.
cy.request({
method: 'POST',
url: '/index.php?p=sys001',
form: true,
body: {
username: 'user',
password_tx: 'pass'
}
})
This is the complete testcase for the issue. Added comments to make them understandable.
it("login via form spoof", () => {
cy.get("div#mDiv > form").invoke("attr", "action").then(($action) => { //get
the attribute of 'action' and pass encoded uname and pwd to it
let username = Cypress.env("username");
let password = Cypress.env("password");
cy.intercept("POST", $action, (req) => { //post request and populate body
// intercepting the POST form to spoof it.
req.body = $action + encodeURIComponent(username)+ encodeURIComponent(password)
})
.as("loginForm"); //alias
});
cy.get("div#mDiv > div.login > form")
.submit(); //Submit the form after locating it.
});
Is it possible to implement windows and jwt authentication schemes in same project?
I need windows authentication to catch user without any login page and jwt to handle roles with any other page and wep api.
Yes, you can add multiple Authentication schemes to your application. Refer to the following link
I finally got the both working. I didn't find anything solved example on internet, hopefully this would help anyone looking for answers.
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IISDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "Bearer";
}).AddJwtBearer("Bearer", options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
//ValidAudience = "the audience you want to validate",
ValidateIssuer = false,
//ValidIssuer = "the isser you want to validate",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myapisecretkey")),
ValidateLifetime = true, //validate the expiration and not before values in the token
ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
};
});
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireClaim(ClaimTypes.Name, "MyAPIUser").Build());
});
Then select the authentication scheme you want to use on particular controller by decorating it.
[Route("api/MyController")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class MyController : Controller
I see that it is relatively easy to add docs to swagger UI for custom endpoints in baucis.
var controller = baucis.rest('User');
controller.swagger.apis.push({
'path': '/users/login',
'description': 'Logs a user in',
'operations': [
{
'httpMethod': 'POST',
'nickname': 'Login',
'responseClass': 'User',
'summary': 'Requests auth token given username and password'
}]})
However, in this case above, I'd like to set the response class to {token : string} instead of 'User', and set parameters to {username: string, password: string}, so that the 'Try it out!' button works.
Any ideas how I would go about this? Or if it is possible in baucis-swagger?
Seems the baucis object above just follows the swagger specification.
Adding a parameters definitions object array, and a responses definition object array to the object above solves my problem.