Spring Security5 学习3 - 实现多个登陆页面

Spring Security5(3)实现多个登陆页面

在一个网页应用中,我们经常需要做到不同的用户有不同的登录页面,以及登陆之后展示不同的页面;不同的用户之间不能访问互相访问网址等等。这里就需要 Spring Security 来实现多个登陆页面。

这里首先使用 idea 创建一个新的 Spring Boot 应用,在功能选择菜单,我们选择:

  • spring security
  • thymeleaf
  • spring mvc
  • springboot devtools
  • lombok

这些功能模块,进入项目,首先在 /resources/templates 下创建 adminuser 两个文件夹,用来存放不同的登陆页面和首页。

在这里插入图片描述

首先给出 admin 的登陆页面:

<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Admin login page</title>
</head>
<body>
<h2>Welcome to admin login page</h2>
<form th:action="@{/admin/login}" method="post">
    <div id="loginTable">
        <table>
            <tbody>
            <tr>
                <td>
                    <label for="username">UserName</label>
                </td>
                <td>
                    <input type="text" id="username" name="username" />
                </td>
            </tr>
            <tr>
                <td>
                    <label for="password">Password</label>
                </td>
                <td>
                    <input id="password" type="password" name="password" />
                </td>
            </tr>
            <tr>
                <td>
                    <input type="submit" value="sign in" />
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <div class="error" th:if="${param.error}">
                        Invalid username add/or password.
                    </div>
                    <div class="info" th:if="${param.logout}">
                        You have been logged out.
                    </div>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
</form>
</body>
</html>

然后是 home 页面:

<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8" >
    <title>Admin home page</title>
</head>
<body>
    <h2>Welcome to admin home page</h2>
    <form th:action="@{/admin/logout}" method="post">
        <input type="submit" value="sign out" />
    </form>
</body>
</html>

home 页面中只有一个退出登陆的按钮。

然后是 user 的登陆页面:

<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>User login page</title>
</head>
<body>
<h2>Welcome to user login page</h2>
<form th:action="@{/user/login}" method="post">
    <div id="loginTable">
        <table>
            <tbody>
            <tr>
                <td>
                    <label for="username">UserName</label>
                </td>
                <td>
                    <input type="text" id="username" name="username" />
                </td>
            </tr>
            <tr>
                <td>
                    <label for="password">Password</label>
                </td>
                <td>
                    <input id="password" type="password" name="password" />
                </td>
            </tr>
            <tr>
                <td>
                    <input type="submit" value="sign in" />
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <div class="error" th:if="${param.error}">
                        Invalid username add/or password.
                    </div>
                    <div class="info" th:if="${param.logout}">
                        You have been logged out.
                    </div>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
</form>
</body>
</html>

然后是 home 页面:

<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8" >
    <title>User home page</title>
</head>
<body>
<h2>Welcome to user home page</h2>
<form th:action="@{/user/logout}" method="post">
    <input type="submit" value="sign out" />
</form>
</body>
</html>

写完了之后,需要创建配置文件,来注册这两组登陆页面和主页:

package com.spring.security.demo.demo;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("user/home");
        registry.addViewController("/admin/login").setViewName("admin/login");
        registry.addViewController("/admin/home").setViewName("admin/home");
        registry.addViewController("/user/login").setViewName("user/login");
        registry.addViewController("/user/home").setViewName("user/home");
    }
}

这里直接通过实现接口 WebMvcConfiguraraddViewControllers 方法来注册这几个页面。

注册完成之后,为了实现权限的管理,需要继承 WebSecurityConfigurerAdapter 重写 configure 方法:

package com.spring.security.demo.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.jaas.memory.InMemoryConfiguration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class SecurityConfig {
    @Configuration
    @Order(1)
    public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/admin/**")
                    .authorizeRequests()
                    .antMatchers("/css/**").permitAll()
                    .anyRequest()
                    .authenticated()

                    .and()
                    .formLogin()
                    .loginPage("/admin/login")
                    .defaultSuccessUrl("/admin/home")
                    .permitAll()

                    .and()
                    .logout()
                    .logoutUrl("/admin/logout")
                    .permitAll();
        }
    }

    @Configuration
    @Order(2)
    public static class UserSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/user/**")
                    .authorizeRequests()
                    .antMatchers("/css/**").permitAll()
                    .anyRequest()
                    .authenticated()

                    .and()
                    .formLogin()
                    .loginPage("/user/login")
                    .defaultSuccessUrl("/user/home")
                    .permitAll()

                    .and()
                    .logout()
                    .logoutUrl("/user/logout")
                    .permitAll();
        }
    }
    // 配置两个用户的用户名和密码的第一种方法
    //    @Autowired
//    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//        auth.inMemoryAuthentication().withUser("user")
//                .password(encoder().encode("123456")).roles("USER");
//        auth.inMemoryAuthentication().withUser("admin")
//                .password(encoder().encode("123456")).roles("ADMIN");
//    }

    // 配置两个用户的用户名和密码的第二种方法
    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(
                User
                .withUsername("user")
                .password(encoder().encode("123456"))
                .roles("USER").build()
        );

        manager.createUser(
                User
                .withUsername("admin")
                .password(encoder().encode("123456"))
                .roles("ADMIN")
                .build()
        );

        return manager;
    }

    // 实现密码加密的方式
    @Bean
    public static PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }
}

由于我们有两个用户,所有就需要重写两次方法。

然后,启动 springboot 程序,输入 /user/login 即可看到 user 登陆界面:

在这里插入图片描述

同理,输入 /admin/user 即可看到 admin 登陆页面:

在这里插入图片描述

但是,我们发现,这两者可以互相登陆,比如输入 admin 的密码和用户名,可以登入 user 的 home 页:

在这里插入图片描述

这里,我们需要对两者的权限进行限制,在配置文件,进行如下修改:

    @Configuration
    @Order(1)
    public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/admin/**")
                    .authorizeRequests()
                    .antMatchers("/css/**").permitAll()
                    .antMatchers("/admin/**").hasRole("ADMIN")
                    .anyRequest()
                    .authenticated()

                    .and()
                    .formLogin()
                    .loginPage("/admin/login")
                    .defaultSuccessUrl("/admin/home")
                    .permitAll()

                    .and()
                    .logout()
                    .logoutUrl("/admin/logout")
                    .permitAll();
        }
    }

    @Configuration
    @Order(2)
    public static class UserSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/user/**")
                    .authorizeRequests()
                    .antMatchers("/css/**").permitAll()
                    .antMatchers("/user/**").hasRole("USER")
                    .anyRequest()
                    .authenticated()

                    .and()
                    .formLogin()
                    .loginPage("/user/login")
                    .defaultSuccessUrl("/user/home")
                    .permitAll()

                    .and()
                    .logout()
                    .logoutUrl("/user/logout")
                    .permitAll();
        }
    }

antMatchers("/css/**").permitAll() 之后,添加 antMatchers("...").hasRole("...") 进行权限管理。

然后,就发现,使用 user 登陆 admin,会出现 403 错误,Forbidden。

在这里插入图片描述

重写 configure 方法中,http对象后面方法的含义

  • antMatcher:用于匹配路径
  • authorizeRequests:允许基于{@link HttpServletRequest}使用
  • antMatchers:映射 antMatcher 中的所有请求方式。
  • permitAll:该 URLs 可以被任何人访问
  • hasRoles:用来设置该 URLs 可以特定的用户访问的快捷方式
  • anyRequest:映射所有的请求
  • authenticated:用以指出这些 URLs 可以被任何授权的用户访问
  • loginPage:如果必须要认证,将会重定向到特定的登陆页面
  • formLogin:指定支持基于表单的身份验证
  • defaultSuccessUrl:如果用户在安全认证之前并未访问一个安全的网页,在认证成功之后,用户将会被重定向到指定的URL。
  • and:允许自定义要使用的{@link SecurityExpressionHandler}。
  • logout:提供登陆支持。
  • logoutUrl:触发注销的URL(默认为“/log out”)。如果 CSRF 保护是开启的(默认的),那么请求也必须是 POST。
  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Security中,可以使用CAS(Central Authentication Service)来实现单点登录(SSO)功能。如果需要使用多个CAS服务器进行校验切换,可以按照以下步骤进行操作: 1. 配置多个CAS服务器的URL 在Spring Security的配置文件中,可以配置多个CAS服务器的URL,如下所示: ``` <bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter"> <property name="casServerUrlPrefix" value="https://cas1.example.com/cas"/> <property name="serviceProperties" ref="serviceProperties"/> </bean> <bean id="casAuthenticationFilter2" class="org.springframework.security.cas.web.CasAuthenticationFilter"> <property name="casServerUrlPrefix" value="https://cas2.example.com/cas"/> <property name="serviceProperties" ref="serviceProperties"/> </bean> ``` 2. 配置多个CAS服务票据校验器 在Spring Security的配置文件中,可以配置多个CAS服务票据校验器,如下所示: ``` <bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"> <property name="ticketValidator"> <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator"> <constructor-arg value="https://cas1.example.com/cas"/> </bean> </property> <property name="authenticationUserDetailsService"> <bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"> <constructor-arg ref="userDetailsService"/> </bean> </property> <property name="serviceProperties" ref="serviceProperties"/> </bean> <bean id="casAuthenticationProvider2" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"> <property name="ticketValidator"> <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator"> <constructor-arg value="https://cas2.example.com/cas"/> </bean> </property> <property name="authenticationUserDetailsService"> <bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"> <constructor-arg ref="userDetailsService"/> </bean> </property> <property name="serviceProperties" ref="serviceProperties"/> </bean> ``` 3. 配置多个CAS服务过滤器 在Spring Security的配置文件中,可以配置多个CAS服务过滤器,如下所示: ``` <bean id="casProcessingFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager"/> </bean> <bean id="casProcessingFilter2" class="org.springframework.security.cas.web.CasAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager2"/> </bean> ``` 4. 配置多个认证管理器 在Spring Security的配置文件中,可以配置多个认证管理器,如下所示: ``` <security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref="casAuthenticationProvider"/> </security:authentication-manager> <security:authentication-manager alias="authenticationManager2"> <security:authentication-provider ref="casAuthenticationProvider2"/> </security:authentication-manager> ``` 通过以上步骤,就可以实现Spring Security中使用多个CAS服务器进行校验切换。在使用时,只需要在需要校验的面中指定使用哪个CAS服务器即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值