首页 \ 问答 \ 使用JSP作为视图引擎注销的spring boot安全性不起作用(spring boot security using JSP as view engine logout does not work)

使用JSP作为视图引擎注销的spring boot安全性不起作用(spring boot security using JSP as view engine logout does not work)

嗨,我正在尝试使用JSP作为视图引擎实现Spring启动Web应用程序。 我正在学习本教程: http//www.mkyong.com/spring-security/spring-security-hello-world-annotation-example/我知道教程没有使用spring boot。 无论如何,我设法实现了一个基本的登录功能。 但问题是,当我尝试注销时,它不起作用并向我显示“白标错误页面”,并显示消息“此应用程序没有明确映射/错误,因此您将此视为后备。” 并且不显示任何其他特定消息。

比如说,当我尝试登录“受管理”页面时,这是受保护的页面。 登录页面出现,我可以成功登录。但是当我点击注销时,出现上述错误,并且在控制台上也没有显示任何错误。 当我转到上一个网址“/ admin”时,它仍然显示它已与之前的用户一起登录。

由于它在控制台和网页上没有显示任何错误,我无法调试问题。 我是Spring Web应用程序的新手,所以请解释我的错误以及如何解决问题。

这是我的主要Application.java文件

@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
    private static final Logger LOGGER = LoggerFactory.getLogger(Application.class.getName());

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        LOGGER.info("Starting Main Application...");
        SpringApplication.run(Application.class, args);
        LOGGER.info("Access URLs: http://127.0.0.1:8080\n");
    }

}

这是我的application.properties文件

spring.mvc.view.prefix= /WEB-INF/jsp/
spring.mvc.view.suffix= .jsp

这是我的SecurityConfig.java文件

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("user").password("user").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").access("hasRole('ADMIN')")
            .antMatchers("/user/**").access("hasRole('ADMIN') or hasRole('USER')")
            .antMatchers("/index").permitAll()
            .antMatchers("/").permitAll()
        .and()
            .formLogin()
        .and()
            .logout()
            .logoutSuccessUrl("/");
    }
}

这是我的MainController.java

@Controller
public class MainController {
    private static final Logger LOGGER = LoggerFactory.getLogger(MainController.class);

    @RequestMapping({"/index", "/"})
    public String index(Model model) {
        model.addAttribute("title", "Spring Web Application example");
        model.addAttribute("message", " This is Spring Web Application example using Spring boot, JSP");
        LOGGER.debug("Inside MainController.index() method");
        return "index";
    }

    @RequestMapping(value = "/admin**", method = RequestMethod.GET)
    public String adminPage(Model model) {
        model.addAttribute("title", "Spring Security Web Application example");
        model.addAttribute("message", "This is a protected page");
        model.addAttribute("h2", "only user with ADMIN role should be able to access this page!");
        return "admin";
    }

    @RequestMapping(value = "/user**", method = RequestMethod.GET)
    public String userPage(Model model) {
        model.addAttribute("title", "Spring Security Web Application example");
        model.addAttribute("message", "This is a protected page");
        model.addAttribute("h2", "only user with either USER or ADMIN role should be able to access this page!");
        return "user";
    }

}

我排除了jsp文件和pom文件,如果你想查看整个项目,请查看我的github存储库https://github.com/agthumoe/spring-boot-security

谢谢


Hi I'm trying to implement a spring boot web application using JSP as view engine. I'm following this tutorial as a basic: http://www.mkyong.com/spring-security/spring-security-hello-world-annotation-example/ I know that the tutorial didn't use spring boot. Anyway, I managed to implement a basic login thing. But the problem is that when I try to logout, it does not work and show me "White label error page" with the message saying "This application has no explicit mapping for /error, so you are seeing this as a fallback." and does not show any other specific messages.

Say for example, when I tried to login to "admin" page which is protected page. The login page appeared and I can successfully logged in. But when I clicked logout, the above error occurs and did not show any error on console as well. When I went to the previous url "/admin", it still showed that it was logged in with the previous user.

Since it doesn't show any error on console and on the web page, I have no clue to debug the issue. I'm very new to Spring web application, so please explain me what's wrong and how to fix the issue.

This is my main Application.java file

@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
    private static final Logger LOGGER = LoggerFactory.getLogger(Application.class.getName());

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        LOGGER.info("Starting Main Application...");
        SpringApplication.run(Application.class, args);
        LOGGER.info("Access URLs: http://127.0.0.1:8080\n");
    }

}

This is my application.properties file

spring.mvc.view.prefix= /WEB-INF/jsp/
spring.mvc.view.suffix= .jsp

This is my SecurityConfig.java file

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("user").password("user").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").access("hasRole('ADMIN')")
            .antMatchers("/user/**").access("hasRole('ADMIN') or hasRole('USER')")
            .antMatchers("/index").permitAll()
            .antMatchers("/").permitAll()
        .and()
            .formLogin()
        .and()
            .logout()
            .logoutSuccessUrl("/");
    }
}

This is my MainController.java

@Controller
public class MainController {
    private static final Logger LOGGER = LoggerFactory.getLogger(MainController.class);

    @RequestMapping({"/index", "/"})
    public String index(Model model) {
        model.addAttribute("title", "Spring Web Application example");
        model.addAttribute("message", " This is Spring Web Application example using Spring boot, JSP");
        LOGGER.debug("Inside MainController.index() method");
        return "index";
    }

    @RequestMapping(value = "/admin**", method = RequestMethod.GET)
    public String adminPage(Model model) {
        model.addAttribute("title", "Spring Security Web Application example");
        model.addAttribute("message", "This is a protected page");
        model.addAttribute("h2", "only user with ADMIN role should be able to access this page!");
        return "admin";
    }

    @RequestMapping(value = "/user**", method = RequestMethod.GET)
    public String userPage(Model model) {
        model.addAttribute("title", "Spring Security Web Application example");
        model.addAttribute("message", "This is a protected page");
        model.addAttribute("h2", "only user with either USER or ADMIN role should be able to access this page!");
        return "user";
    }

}

I excluded the jsp files and pom file, if you would like to see the whole project, please have a look at my github repository https://github.com/agthumoe/spring-boot-security

Thanks


原文:https://stackoverflow.com/questions/35904252
更新时间:2021-10-16 21:10

最满意答案

好吧,既然我有更多的时间来看待这个没有匆忙上班,我就看到了这个问题。 您应该做的是使用注入的工厂来创建ApplyChangesCommand 。 然后,对于VM的单元测试,您只需验证该命令是否返回工厂创建的命令。 以下是一个例子:

public class MyViewModel
{
    private MyCustomCommandFactory _commandFactory;
    private void _somethingToExecute;

    public MyViewModel(MyCustomCommandFactory commandFactory)
    {
        _commandFactory = commandFactory;
    }

    public ICommand ApplyChangesCommand  
    { 
        get 
        { 
            return _commandFactory.Create(_somethingToExecute, e=>true);
        }
    }
}

这假设您希望每次调用get时都要创建一个新命令(这似乎就是您设置它的方式)。 如果您只想为VM的生命周期创建一个命令,显然您可以通过VM构造函数中的工厂创建命令。

要对此进行单元测试,您可以执行以下操作:

[Test]
public void ApplyChangesCommand_Always_ReturnsFactoryCreatedCommand
{
    Mock<ICommand> mockCreatedCustomCommand = new Mock<ICommand>();
    Mock<MyCustomCommandFactory> mockCommandFactory = new Mock<MyCustomCommandFactory>();
    mockCreatedCustomCommand.Setup(p => p.Create(It.IsAny<Action>(), e => true))
                            .Returns(mockCreatedCustomCommand.Object);
    Assert.That(systemUnderTest.ApplyChangesCommand, Is.SameAs(mockCreatedCustomCommand.Object));
}

(无论你的代表实际是什么,都要改变Action )。

这就是为VM命令进行单元测试所需的全部内容。 如果您想测试行为是您所期望的(意味着,它执行传入的委托并使用该委托返回预期值),那么这就是验收测试的领域。

注意:我在测试示例中使用了Moq模拟框架语法。

就个人而言,我不会将这样的代表传递给一个Command 。 我会注入任何Command需要的东西,并拥有Command所有逻辑,在那里它更容易进行单元测试,并且对VM有更宽松的依赖性。


Ok, now that I've had more time to look at this not being rushed at work, I see the issue. What you should do is use an injected factory to create the ApplyChangesCommand. Then for unit testing your VM, you just verify that the command returns the factory created command. Below is an example:

public class MyViewModel
{
    private MyCustomCommandFactory _commandFactory;
    private void _somethingToExecute;

    public MyViewModel(MyCustomCommandFactory commandFactory)
    {
        _commandFactory = commandFactory;
    }

    public ICommand ApplyChangesCommand  
    { 
        get 
        { 
            return _commandFactory.Create(_somethingToExecute, e=>true);
        }
    }
}

This assumes you're wanting to create a new command every time the get is called (which seems to be how you have it set up). If you want just a single command created for the life of the VM, obviously you can just create the command via the factory in the VM constructor.

To unit test this, you can do something like this:

[Test]
public void ApplyChangesCommand_Always_ReturnsFactoryCreatedCommand
{
    Mock<ICommand> mockCreatedCustomCommand = new Mock<ICommand>();
    Mock<MyCustomCommandFactory> mockCommandFactory = new Mock<MyCustomCommandFactory>();
    mockCreatedCustomCommand.Setup(p => p.Create(It.IsAny<Action>(), e => true))
                            .Returns(mockCreatedCustomCommand.Object);
    Assert.That(systemUnderTest.ApplyChangesCommand, Is.SameAs(mockCreatedCustomCommand.Object));
}

(Change Action out for whatever your delegate actually is).

This is all you should have to unit test for a VM's command. If you're wanting to test that the behavior is what you expect (meaning, it executes the passed in delegate and returns the expected value using that delegate), then that's the realm of an acceptance tests.

Note: I used the Moq mocking framework syntax in my test example.

Personally, I wouldn't be passing in delegates like that to a Command. I would instead inject whatever the Command needs and have all the logic inside the Command, where it is more easily unit tested in there, and has a looser dependency on the VM.

相关问答

更多
  • 好吧,既然我有更多的时间来看待这个没有匆忙上班,我就看到了这个问题。 您应该做的是使用注入的工厂来创建ApplyChangesCommand 。 然后,对于VM的单元测试,您只需验证该命令是否返回工厂创建的命令。 以下是一个例子: public class MyViewModel { private MyCustomCommandFactory _commandFactory; private void _somethingToExecute; public MyViewModel ...
  • 由于您使用MockBehavior.Strict因此抛出了NullReferenceException 。 文件说: 导致此模拟始终为没有相应设置的调用抛出异常。 也许ArticleDataGridViewModel的构造ArticleDataGridViewModel调用您尚未设置的服务的其他方法。 另一个问题是,您直接调用模拟方法。 相反,您应该调用视图模型的方法,该方法调用此方法。 [TestMethod] public void GetArticleBody_Test_Valid() { / ...
  • 这个 Command="{Binding DataContext.CmdTestButtonClicked}" 意味着Command将在按钮绑定的对象中查找名为DataContext的属性。 如果按钮的DataContext是GlobalSettingsVM则应该可以: Command="{Binding CmdTestButtonClicked}" This Command="{Binding DataContext.CmdTestButtonClicked}" Implies that th ...
  • 由于类遵循单例模式,因此行为应该没有任何差异。 任何引用单例的东西都不会关心如何限制类的构造,只关注类的实例是否存在。 问题可能在于ViewModel的PropertyChanged事件与Command上的CanExecuteChanged之间缺少正确的链接。 There shouldn't be any difference in the behavior due to the fact that a class follows the singleton pattern. Anything with a ...
  • 首先,你试图在一次测试中测试两个独立的东西。 将逻辑分离到更集中的测试将使您在重构时更少的头痛。 请考虑以下内容: SearchTerm_InvokesExecuteSearchAfterThrottle SpinnerVisibility_VisibleWhenExecuteSearchIsExecuting 现在,您可以单独验证每个功能的单元测试。 如果一个失败了,你就会确切地知道哪个期望被打破了,因为只有一个。 现在,进行实际测试...... 根据您的代码,我假设您使用的是NUnit , FakeIt ...
  • 您可以使用MvxAsyncCommand (请参阅: implementation )而不是MvxCommand ,并将已发布的GetAuthorisationCommand类型从ICommand更改为IMvxAsyncCommand (但该接口尚未通过nuget提供),然后您可以调用 await vm.GetAuthorisationToken.ExecuteAsync(); You can use MvxAsyncCommand (see: implementation) instead of Mvx ...
  • 看看你的尝试,我们需要修复一些事情,首先你的CanExecute不应再涉及parameter了: public bool CanExecute(object parameter) { return Paddle1 != null; } 其次你的XAML绑定是错误的,你已经在你的可视化树中运行了你的视图模型的DataContext,你只需要一个简单的Binding,其中一些Path指定如下:
  • 你的方法有一个没有使用的对象参数; 考虑测试它; 如果为空则显示对话框,否则将其用作对话框结果文件名 顺便一提; 在viewmodel中放置对话框不符合MVVM - 考虑查找相关代码 your method has got an object parameter which is not used; consider testing it; if empty display the dialog else use it as the dialog result filename by the way; it ...
  • 找到了一种以我试图的方式解决它的方法。 在这里留下答案,以便人们可以使用它: 1)在用户控件的代码隐藏中,创建一个依赖属性。 我选择ICommand,因为在我的ViewModel中我将其设置为DelegateCommmand: public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command", typeof(ICommand), ...
  • 查看反射器中的MenuItem ,我们可以看到MenuItem如何获取Header / InputGesture值,即: private static object CoerceInputGestureText(DependencyObject d, object value) { RoutedCommand command; MenuItem item = (MenuItem) d; if ((string.IsNullOrEmpty((string) value) && ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。