天天看点

项目之用户登录和访问权限的控制(6)

完成后,在src/test/java下的cn.tedu.straw.portal.service.UserServiceTests编写并执行单元测试:

@Test
void login() {
    String username = "13988139111";
    UserDetails userDetails = userService.login(username);
    log.debug("login, user details={}", userDetails);
}      

如果测试通过,就可以把以上获取得到的UserDetails对象应用到UserDetailsServiceImpl的返回值中:

@Component
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private IUserService userService;
   
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return userService.login(username);
    }
}      

17. 用户登录-关于访问控制(相当于拦截器)

在SecurityConfig中重写protected void configure(HttpSecurity http)方法:

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 准备白名单,是不需要登录就可以访问的路径
    String[] antMatchers = {
        "/index.html"
    };
    // 授权设置,是相对固定的配置
    // csrf().disable() > 关闭跨域攻击
    // authorizeRequests() > 对请求进行授权
    // antMatchers() > 配置访问白名单
    // permitAll() > 对白名单中的路径进行授权
    // anyRequest() > 其它的请求
    // authenticated() > 仅经过授权的允许访问,也可以理解为“未被授权将不允许访问”
    // and.formLogin() > 未被授权的将通过登录表单进行验证登录并授权
    http.csrf().disable()
            .authorizeRequests()
            .antMatchers(antMatchers).permitAll()
            .anyRequest().authenticated()
            .and().formLogin();
}      

关于以上代码:

调用参数对象http的链式方法的配置是相对固定的,可以尝试理解,也可以直接套用;

以上调用的antMatchers()相当于使用SpringMVC拦截器时配置白名单,方法的参数中,应该将所有需要被直接放行(不登录即可访问的位置)的路径都添加进来,例如:

String[] antMatchers = {
    "/index.html",
    "/bower_components/**",
    "/css/**",
    "/img/**",
    "/js/**"
};      

至今,主页index.html是不需要登录即可访问的,而其它页面暂时都是需要登录才允许访问的!

18. 用户登录-更换自定义登录页

首先,在项目中添加Thymeleaf的依赖:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>      

自定义的登录页面,将是被设计为HTML模版页,当请求登录的网址时,转发到该HTML模版页,则在项目的src/main/resoueces下创建templates文件夹,这是SpringBoot项目默认使用的模版页面文件夹,不需要配置,在转发时默认就会在这个文件夹中查询HTML模版文件,当文件夹创建完成后,将static文件夹下的login.html文件拖拽到templates文件夹下。

接下来,自定义控制器,设计登录页面的请求路径,在处理该路径的请求时,直接转发到**/templates/login.html**文件,由于Thymeleaf在整合时已经将前缀配置为了/templates/,把后缀配置为了.html,所以在控制器返回的视图名就是login:

@Controller
public class SystemController {
    @GetMapping("/login.html")
    public String login() {
        return "login";
    }
    // 适用于使用@RestController时
    // public ModelAndView login() {
    //    return new ModelAndView("login");
    // }
}      

然后,还需要将以上设计的请求路径添加到配置的白名单中。

完成后,重启项目,在浏览器通过http://localhost:8080/login.html即可看到自定义的登录页面。

目前,通过http://localhost:8080/login.html可以访问到自定义的登录页,并且,通过http://localhost:8080/login还能访问到Spring Security内置的登录页,也就是说,这2个登录页面是共存的!应该通过配置,使得Spring Security始终自动使用我们自定义的登录页!需要在SecurityConfig类的配置中补充添加:

package cn.tedu.straw.portal.security;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }

//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        http.csrf().disable();
//    }

    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 登录页面的URL
        String loginPageUrl = "/login.html";
        // 处理登录请求的URL
        String loginProcessingUrl = "/login";
        // 登录失败后的URL
        String loginFailureUrl = "/login.html?error";
        // 登录成功后的URL
        String loginSuccessUrl = "/index.html";
        // 退出登录的URL
        String logoutUrl = "/logout";
        // 退出登录成功后的URL
        String logoutSuccessUrl = "/login.html?logout";
        // 准备白名单,是不需要登录就可以访问的路径
        String[] antMatchers = {
                loginPageUrl,
                "/index.html",
                "/bower_components/**",
                "/css/**",
                "/img/**",
                "/js/**"
        };
        // 授权设置,是相对固定的配置
        // csrf().disable() > 关闭跨域攻击
        // authorizeRequests() > 对请求进行授权
        // antMatchers() > 配置访问白名单
        // permitAll() > 对白名单中的路径进行授权
        // anyRequest() > 其它的请求
        // authenticated() > 仅经过授权的允许访问,也可以理解为“未被授权将不允许访问”
        // and.formLogin() > 未被授权的将通过登录表单进行验证登录并授权
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers(antMatchers).permitAll()
                .anyRequest().authenticated()
                .and().formLogin()
                .loginPage(loginPageUrl)
                .loginProcessingUrl(loginProcessingUrl)
                .failureUrl(loginFailureUrl)
                .defaultSuccessUrl(loginSuccessUrl)
                .and().logout()
                .logoutUrl(logoutUrl)
                .logoutSuccessUrl(logoutSuccessUrl);
    }

}

      

19. 关于访问权限控制

先准备一下测试使用的URL:

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private IUserService userService;

    // http://localhost:8080/test/user/1
    @GetMapping("/user/{id}")
    public User getUserById(@PathVariable("id") Integer id) {
        return userService.getById(id);
    }

}