初识Springboot Security和Thymeleaf

1.导入thymeleaf页面

首先导入jar,在pom.xml文件中添加:

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

在application.properties中添加配置:

spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.check-template-location=true
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.mode=HTML
spring.thymeleaf.cache=false

最后在templates目录下添加需要用到的界面:
在这里插入图片描述
新增controller:

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Controller
public class KongfuController{

    private final String PREFIX = "pages/";

    @GetMapping("/")
    public String index(){
        return "welcome";
    }

    @GetMapping("/userLogin")
    public String loginPage(){
        return PREFIX + "login";
    }

    @GetMapping("/level1/{path}")
    public String level1(@PathVariable("path") String path){
        return PREFIX + "level1/" + path;
    }

    @GetMapping("/level2/{path}")
    public String level2(@PathVariable("path") String path){
        return PREFIX + "level2/" + path;
    }

    @GetMapping("/level3/{path}")
    public String level3(@PathVariable("path") String path){
        return PREFIX + "level3/" + path;
    }

}

运行application后,访问http://localhost:8080,就可以看到welcome.html在的内容了

哪有这么容易,这一步搞了好久,就是这么都找不到头绪,最后原因可能是因为我在idea环境准备好之前去新建了这个controller,导致没把它当成java的class去编译,删掉重新建才成功的

2.使用Security

导包:

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

编写web安全验证类
1.使用@EnableWebSecurity注解
2.继承WebSecurityConfigurerAdapter
3.重写configure(HttpSecurity http),对请求验证规则进行配置
4.重写configure(AuthenticationManagerBuilder auth) ,定义验证的账号和密码,目前只保存在内存中
代码:

package com.example.demo.config;

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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception{
		//定制请求的授权规则
		http.authorizeRequests().antMatchers("/").permitAll()
			.antMatchers("/level1/**").hasRole("VIP1")
			.antMatchers("/level2/**").hasRole("VIP2")
			.antMatchers("/level3/**").hasRole("VIP3");
		//开启自动配置的登陆功能
		http.formLogin();
		
		//开启自动配置的注销功能
		//1、/logout注销
		//2、注销成功,默认重定向到/login?logout,logoutSuccessUrl方法重写,这里把它指向了首页
		http.logout().logoutSuccessUrl("/");
		
		//开启记住我功能
		//1、登陆成功后,保存登陆信息到浏览器cookie中
		//2、点击注销会删除这个cookie
		http.rememberMe();
		
	}
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception{
		//定制认证规则
		auth.inMemoryAuthentication()
			.withUser("za").password("123456").roles("VIP1")
			.and()
			.withUser("zx").password("123456").roles("VIP1","VIP2")
			.and()
			.withUser("zs").password("123456").roles("VIP1","VIP2","VIP3");
	}
}

访问http://localhost:8080/login,这是Security自带的login页面
测试使用这些定义的账号密码,发现无法登录,提示未定义的“null”用户
原因是,在2.0的springboot中,对明文的用户名和密码做了编码处理,因此还需要另外编写一个Encoder:

package com.example.demo.config;

import org.springframework.security.crypto.password.PasswordEncoder;

public class MyPasswordEncoder implements PasswordEncoder {
	
	@Override
	public String encode(CharSequence charSequence) {
		return charSequence.toString();
	}

	@Override
	public boolean matches(CharSequence charSequence, String s) {
		return s.equals(charSequence.toString());
	}
}

MySecurityConfig中的configure(AuthenticationManagerBuilder auth)应改为:

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception{
		//定制认证规则
		auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder())
			.withUser("za").password("123456").roles("VIP1")
			.and()
			.withUser("zx").password("123456").roles("VIP1","VIP2")
			.and()
			.withUser("zs").password("123456").roles("VIP1","VIP2","VIP3");
	}

再次登录,成功!

3.Thymeleaf使用Security

导包:

		<dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>

首页welcome.html,在html标签中添加 xmlns:sec=“https://www.thymeleaf.org/thymeleaf-extras-springsecurity5”
1.sec:authorize=“isAuthenticated()”,未验证登录,提示游客登录
2.sec:authentication=“name”、sec:authentication=“principal.authorities”,完成验证登录,提示登录用户名和角色信息
3.sec:authorize=“hasRole(‘VIP1’)”,根据角色信息来展示“武功秘籍”

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <meta charset="UTF-8">
    <title>武林秘籍</title>
</head>
<body>
<h1 align="center">欢迎来到武林秘籍管理系统</h1>
<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">		
    <h2 align="center"><span sec:authentication="name"></span>,你好,你的角色有:					
    	<span sec:authentication="principal.authorities"></span>
    </h2>
    <div>
        <form action="#" th:action="@{/logout}" method="post">					
            <input type="submit" value="注销">
        </form>
    </div>
</div>
<div sec:authorize="!isAuthenticated()">		
    <h2 align="center">游客你好,请<a th:href="@{/userLogin}">登录</a>查看秘籍内容</h2>
</div>
<div sec:authorize="hasRole('VIP1')">
	<h3>普通</h3>
	<ul>
	    <li><a th:href="@{/level1/1}">罗汉拳</a></li>
	    <li><a th:href="@{/level1/2}">武当剑</a></li>
	</ul>
</div>
<div sec:authorize="hasRole('VIP2')">
	<h3>高级</h3>
	<ul>
	    <li><a th:href="@{/level2/1}">太极拳</a></li>
	    <li><a th:href="@{/level2/2}">纵云梯</a></li>
	</ul>
</div>
<div sec:authorize="hasRole('VIP3')">
	<h3>绝世</h3>
	<ul>
	    <li><a th:href="@{/level3/1}">葵花宝典</a></li>
	    <li><a th:href="@{/level3/2}">独孤九剑</a></li>
	</ul>
</div>
</body>
</html>

4.自定义登录页面

在开始的controller中,定义了一个userLogin,现在把它作为登录界面
1.重写login.html:

<html lang="en"><head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>登陆页</title>
    </head>
<body>
<div class="container">
    <form class="form-signin" method="post" action="/userLogin">
        <h2 class="form-signin-heading">请登录</h2>
        <p>
            <label for="username" class="sr-only">用户名</label>
            <input type="text" id="username" name="user" class="form-control" placeholder="Username" required="" autofocus="">
        </p>
        <p>
            <label for="password" class="sr-only">密码</label>
            <input type="password" id="password" name="pwd" class="form-control" placeholder="Password" required="">
        </p>
        <p><input type="checkbox" name="remember"> Remember me on this computer.</p>
        <input name="_csrf" type="hidden" value="26c20555-5ee2-4458-851f-0bb0d3530957">
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
    </form>
</div>
</body></html>

这里我就是把Security自带的页面拷贝下来而已,把username输入框name改成了user,password输入框name输入框改成了pwd,把“记住我”的勾选框名称改成了remember,最后把表单提交的action改为/userLogin。

现在可以在configure(HttpSecurity http)方法中http自定义登陆界面信息:

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

		http.authorizeRequests().antMatchers("/").permitAll()
			.antMatchers("/level1/**").hasRole("VIP1")
			.antMatchers("/level2/**").hasRole("VIP2")
			.antMatchers("/level3/**").hasRole("VIP3");

		// usernameParameter修改获取用户名的name
		// passwordParameter修改获取密码的name
		// loginPage修改处理登录的方法
		http.formLogin().usernameParameter("user").passwordParameter("pwd")
				.loginPage("/userLogin");
				
		http.logout().logoutSuccessUrl("/");

		http.rememberMe().rememberMeParameter("remember");
	}

还没有成功,使用自定义的登录界面登录,发现点击登陆按钮后,发生 403 Forbidden 错误
查找资料后发现,是因为拷贝过来的页面中,包含了Springboot的跨域信息:

<input name="_csrf" type="hidden" value="26c20555-5ee2-4458-851f-0bb0d3530957">

在方法中,添加一句:

http.csrf().disable();

问题解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值