Just a quick one to see whether it is possible to run a block of code after the bootstrap's init() has completed?
Hows the best way to go about it?
I have some external systems I need to connect to, and I want to show an 'index' page saying 'Connecting to sub systems' or something similar whilst this block completes, and then once its done the application works as normal.
Am I right in thinking you cant access a page until after bootstrap? Is there a simple way to restrict people accessing other parts of the system whilst this service runs? Does this seem feasible?
Cheers for any help!
Based on your requirement as you also pointed out bootstrap is not your friend. you need a view and controller for your screen and a service for your connection logic to external systems. You also need a flag or a method for sanity check of the communication within the scope of application or session. Then I would suggest to create a filter and check if you have the connections, if not redirect them to the controller that will connect it.
Sudo:
class ConnectionFilters {
def filters = {
loginCheck(controller: '*', action: '*') {
before = {
if (!session.connection ) {
redirect(controller:'connection',action: 'connect')
return false
}
}
}
}
}
class controller {
def connectionService
def connect (){
try {
connectionService.connectTo('systemx')
connectionService.connectTo('systemy')
connectionService.connectTo('systemz')
}
catch(e){
session.connection = false
redirect view:'error'
}
session.connection = true
}
}
class ConnectionService {
def connectTo(systemname){
....
}
}
Related
I wanna to check if the browser is IE and do something in razor page.
I just made a function in razor page to do that.
However, I think use the function to check if the browser is IE in every razor page is redundant. For independent user, I just need to check this only one time and set a global variable that IsIE=true/false . And other page will easily know that if it is IE.
The question is how can I get/set a global variable in razor page?
Thank you.
————————————————
To #Neville Nazerane ,here is the function which to check if is IE:
#{
Boolean IsIE = false;
string UA = Context.Request.Headers["User-Agent"].ToString();
if (UA.Contains("Trident") || UA.Contains("MSIE"))
{
IsIE = true;
}
else
{
IsIE = false; ;
}
if (IsIE == true)
{
}
else
{
}
}
HTTP requests work by clients sending a request (with header and body) to your server. Your server can then access this info and send a response. This doesn't create any persistent (ongoing) connection between the server and client. This means there is no permanent link between your server and each client. Any global variable you declare will be global for your server's web application and will be common for every client.
What you are trying to do here is create variables isolated from each client's connection. Normally this is done with the help of Session or Cookie variable. But in this case, I don't see how this will improve any performance over the code you have written. In your code, you are trying to access the Http Headers from the request. Cookies and session variables are also accessed in a very similar way. If anything fetching directly from headers must have a slightly better performance. If you are trying to clean up your code so you don't have to write this on every page, services could be quite helpful.
You can create a class for service something like this:
public class AgentChecker
{
public bool IsIE { get; set; }
// makes sure check is done only when object is created
public AgentChecker(IHttpContextAccessor accessor)
{
string UA = accessor.HttpContext.Request.Headers["User-Agent"].ToString();
if (UA.Contains("Trident") || UA.Contains("MSIE"))
{
IsIE = true;
}
else
{
IsIE = false;
}
}
// optional to simplify usage further.
public static implicit operator bool(AgentChecker checker) => checker.IsIE;
}
In your startup class add the following:
// to access http context in a service
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// makes sure object is created once per request
services.AddScoped<AgentChecker>();
Once this is set up, in your view you can use:
#inject AgentChecker checker
#* if you didn't create the implicit operator, you can use if (checker.IsIE) *#
#if (checker)
{
<div>Is ie</div>
}
else
{
<div>not ie</div>
}
The inject goes at the top of any view page you would like to use this in. While this still creates a new object each request, it is cleaner to use and only creates one object no matter how many partial views you are using.
I'd like to use Glimpse for our prod site, but I want to limit who can turn it on. This is mentioned
here, but currently our site does not have a login, nor is set up for Windows Authentication. Can I restrict access via IP address? Also, if I turn glimpse on who will see the results on the page? Just me or everyone?
You have to create a custom runtime policy. It's actually pretty trivial. Here's a quick and dirty mod to the sample runtime policy in the Glimpse docs that only allows a particular IP:
using Glimpse.AspNet.Extensions;
using Glimpse.Core.Extensibility;
namespace Users.Web.Application.Namespace
{
public class GlimpseSecurityPolicy:IRuntimePolicy
{
public RuntimePolicy Execute(IRuntimePolicyContext policyContext)
{
var httpContext = policyContext.GetHttpContext();
if (httpContext.Request.UserHostAddress == "123.123.123.123")
return RuntimePolicy.Off;
return RuntimePolicy.On;
}
public RuntimeEvent ExecuteOn
{
get { return RuntimeEvent.EndRequest; }
}
}
}
I'm using Grails 2.2.3 and the Spring Security ACL plugin 1.1.1, and I'd like to have a URL that is open to the public and the service layer using the #PostAuthorize annotation secures the resource. We're doing it this way because to determine whether a user has access to a particular object we need to look at the object first.
What I'd like to be able to do is in the controller layer catch the AccessDeniedException, then have the browser ask for credentials and try again. I've tried the naive approach of setting the response status to 401 and redirecting back to itself to try again. The problem I ran into is that the browser never asked for credentials.
To put this into code what I'd like to do is in the controller layer:
#Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def controllerAction() {
try {
someService.action()
} catch (AccessDeniedException ade) {
// if logged in show FORBIDDEN, if not ask for credentials and try again
}
}
And the service layer would simply have:
#PostAuthorize("""returnObject.availability == 'ALL'""")
def action() {
PersistedObject.findById(1)
}
Thanks for any help!
I ended up solving the problem, and it turns out I was missing a header that I needed to send along with the 401 status code.
To correct what I have above what you want to do is:
#Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def controllerAction() {
try {
someService.action()
} catch (AccessDeniedException ade) {
if (!springSecurityService.isLoggedIn()) {
response.setHeader 'WWW-Authenticate', 'Basic realm="Grails Realm"' // the missing line
response.sendError HttpServletResponse.SC_UNAUTHORIZED
}
}
The "redirect" I was looking for happens automatically within the browser after credentials are submitted. I was mistaken about needing something specific for the redirect.
Is it possible to inject a Spring bean into a Grails webflow? I tried the following
class CheckoutController {
ShoppingService shoppingService
def checkoutFlow = {
start {
action {
// This attempt to access the service doesn't work
flow.addresses = shoppingService.getOrder()
}
}
}
}
I can access shoppingService from a regular controller action, but I can't access it from an action of the webflow (see above).
add the following to your controller:
def transient shoppingService
There are issues with dependency injection with webflows in controllers that contain traditional actions plus webflows. It worked for me if the traditional action executed first.
see:
GRAILS-7095
GRAILS-4141
Webflows also break notions of defaultAction in mixed controllers. I have found the first webflow wins and becomes the default action.
separately using transient keeps your service from be serialized between flow states. (e.g. don't have to implement serializable)
At first I thought what you listed was pseudocode but I made a sample app using your example and got the NPE as well. I think it may be your flow structure that is the problem. action blocks should go within a flow state. Your flow definition should look something like:
class CheckoutController {
ShoppingService shoppingService
def checkoutFlow = {
start {
action {
flow.addresses = shoppingService.getOrder()
if(flow.addresses) {
showForm()
}
else {
showError()
}
}
on("showForm").to "showForm"
on("showError").to "showError"
}
showError {
...
}
//etc.
}
}
You can definitely use injected services in your web flows. I am guessing that the problem lies in your flow structure.
Could anyone advise a feasible solution to prevent direct access to *.gsp pages on Grails?
After reviewing intercepting '/**.gsp', I found it is impossible to use that as it not only filters out direct access, but also the pages rendering from controllers, etc.
I tried to setup the following in UrlMapping.groovy, even though I can prevent the *.gsp direct access, but I also make a mess to the navigation of the pages; all the links seem to go to home page then.
"/**.gsp" {
isEligible = {
System.err.println("ALL PARAMS: " + params)
request.requestURL.toString().endsWith(".gsp")
}
controller = {
if (request.requestURL.toString().endsWith(".gsp")) {
"public"
} else {
"*"
}
}
action = {
if (request.requestURL.toString().endsWith(".gsp")) {
"home"
} else {
"*"
}
}
}
Once I thought about setup filter like org.springframework.web.filter.OncePerRequestFilter, but not quite sure how to define it probably as Grails tends to generate the web.xml filters section by itself.
Any thoughts?
Thanks a lot!
tom
unfortunately I did not find a solution with UrlMappings.
here is a solution which is little bit ugly but if you use the same layout (for example main.gsp) on all pages you could add this lines to the layout (main.gsp).
<% if (request.requestURL.toString().endsWith(".gsp")) {
response.sendRedirect("${request.contextPath}/")
} %>
this way if the user tries to access the gsp page direct he gets redirected to the home page.
maybe not the best solution but did work for me so far.
cheers shifty
Add these to UrlMappings:
"/**.gsp" {
controller = {
if(request.requestURL.toString().endsWith(".gsp")) {
"forbidden"
} else params.controller
}
}
And create a ForbiddenController and an index.gsp with "Never think of accessing GSPs directly dude." as its content.
Cheers.
according to the grails FAQ the "/**.gsp" configuration in the UrlMapping.groovy should work.
couldn't try it out yet.
How did you add the links to the page ?
Are the links also broken when you use the link tag ?
<g:link controller="book" action="list">Book List</g:link>
What about writing a filter that will be executed on each request ?