stackoverflow rohit
stackoverflow rohit

Reputation: 315

Django to return a view with TokenAuthentication for WebView

I am trying to create a flutter app which will use webview to display authenticated data from my Django App.

Steps Involved:

  1. Flutter app sends authentication request
  2. Django validates the user credentials (user id & Password) and returns authtoken
  3. Flutter then sends a request via a webview to a url (which requires login).

I would like to login the user in webapp using this token and return the webview. If the url does not require authentcation, it works like a charm. When the url requires authentication, I am redirected to the login page and I want users to bypass that using token authentication which is already aquired in Step 1

here is my Django view.

class QuizTake(FormView):
    permission_classes = (IsAuthenticated,)
    form_class = QuestionForm
    template_name = 'question.html'
    result_template_name = 'result.html'
    single_complete_template_name = 'single_complete.html'
    login_template_name='login.html'

      
    def dispatch(self, request, *args, **kwargs):
        self.quiz = get_object_or_404(Quiz, url=self.kwargs['quiz_name'])
        print(self.kwargs['quiz_name'])
        
        """
        Authenticate if the request has token authentication
        """

        if self.quiz.draft and not request.user.has_perm('quiz.change_quiz'):
            raise PermissionDenied

        try:
            self.logged_in_user = self.request.user.is_authenticated()
        except TypeError:
            self.logged_in_user = self.request.user.is_authenticated

        if self.logged_in_user:
            self.sitting = Sitting.objects.user_sitting(request.user,
                                                        self.quiz)
        else:
            self.sitting = self.anon_load_sitting()

        if self.sitting is False:
            print("sitting false")
            if self.logged_in_user:
                return render(request, self.single_complete_template_name)
            else:                
                redirecturl = "/login/?next=/quiz/"+self.kwargs['quiz_name']+"/take/"
                return redirect(redirecturl)
        return super(QuizTake, self).dispatch(request, *args, **kwargs)

Flutter Code

class _QuizLauncherState extends State<QuizLauncher> {
  final String url, authtoken;
  final int userId;
  String quizUrl;
  _QuizLauncherState(this.url,  this.authtoken,this.userId);

  void initState() {
    quizUrl = 'https://test.mysite.com/quiz/$url/take';
    print(quizUrl);
    //for reference https://test.mysite.com/quiz/56df5d90-7f67-45ff-8fe1-7c07728ba9ab/take/
    super.initState();
  }

  Completer<WebViewController> _controller = Completer<WebViewController>();
  final Set<String> _favorites = Set<String>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // This drop down menu demonstrates that Flutter widgets can be shown over the web view.
        actions: <Widget>[
          NavigationControls(_controller.future),
          Menu(_controller.future, () => _favorites),
        ],
      ),          
      body: WebView(
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webViewController) {
          Map<String, String> headers = {"Authorization": "Bearer " + authtoken};
          webViewController.loadUrl(quizUrl, headers: headers);
        },

      ),      
    );
  }
}

Is this possible at all? If there are any alternate ways, please tell me. Basically, I am trying to access a url via webview which requires authentication, using authtoken. Please help.

Upvotes: 6

Views: 1126

Answers (2)

Brian Destura
Brian Destura

Reputation: 12078

You can use custom authentication classes like this, say if you are using Authorization header:

from rest_framework.authentication import BaseAuthentication

class MyCustomAuth(BaseAuthentication):
    def authenticate(self, request):
        auth_method, token = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
        # Get your user via the token here
        if you_got_your_user:
            return user, None
        return None # or raise AuthFailedException


class QuizTake(FormView):
    authentication_classes = (MyCustomAuth, )

This still depends on how your token identifies the user though. For example if you are using JWT, there are existing authentication classes already that handles this for you.

EDIT: Looked at knox documentation from here. If you used knox, then you should probably use their own TokenAuthentication class. Can you try with below code:

from knox.auth import TokenAuthentication

class QuizTake(FormView):
    authentication_classes = (TokenAuthentication, )

Upvotes: 2

Alok Kumar Maurya
Alok Kumar Maurya

Reputation: 139

You can use authentication from rest framework lib like as below code.

import base64
import binascii
from django.contrib.auth import authenticate, get_user_model
from django.middleware.csrf import CsrfViewMiddleware
from django.utils.translation import gettext_lazy as _
from rest_framework import HTTP_HEADER_ENCODING, exceptions
def get_authorization_header(request):
    auth = request.META.get('HTTP_AUTHORIZATION', b'')
    if isinstance(auth, str):
       auth = auth.encode(HTTP_HEADER_ENCODING)
    return auth
class BaseAuthentication:
      raise NotImplementedError(".authenticate() must be overridden.")
      def authenticate_header(self, request):
          pass
class SessionAuthentication(BaseAuthentication):
      user = getattr(request._request, 'user', None)
      if not user or not user.is_active:
          return None
      self.enforce_csrf(request)
      return (user, None)
def enforce_csrf(self, request):
    def dummy_get_response(request):
    return None
    check = CSRFCheck(dummy_get_response)
    check.process_request(request)
    reason = check.process_view(request, None, (), {})
    if reason:
    raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)
class TokenAuthentication(BaseAuthentication):
      keyword = 'Token'
      model = None
      def get_model(self):
          if self.model is not None:
             return self.model
          from rest_framework.authtoken.models import Token
             return Token

Or go through the below link for better understanding [Toke Authorization]

Upvotes: 1

Related Questions