您的位置:首页 > 编程语言 > Java开发

手工配置springboot + spring security + thymeleaf + thymeleaf-extras-springsecurity

2018-03-09 00:00 666 查看
摘要: 本文主要介绍当使用springboot与thymeleaf-extras-springsecurity扩展时如何实现自定义的thymeleaf配置,以及该扩展的集成方法

thymeleaf-extras-springsecurity是thymeleaf模板框架与spring security框架的扩展包,主要实现在thymeleaf的模板页面中可以很方便的调用security框架返回的用户验证和权限信息。因为spring boot并没有对该扩展实现自动配置,因此在使用该扩展时需要自己实现thymeleaf的配置与该扩展的集成。

spring boot中thymeleaf的自动配置

Spring Boot要使用thymeleaf很方便,只需要引入spring-boot-starter-thymeleaf的依赖即可实现自动配置。

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

默认使用的是thymeleaf2,如果想使用thymeleaf3,可以在pom文件中配置thymeleaf和dialect的版本

<!-- pom.xml -->
<properties>
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
</properties>

我这里使用的就是thymeleaf3,因为有我喜欢的html模板,且全面支持html5

spring boot的自动配置已为您按默认配置好了ViewResolvers,您只需将html文件放到src/main/resources/templates下,就可以在controller通过视图名称使用对应的html文件了

如果我们不使用thymeleaf-extras-springsecurity扩展的话,我们只需要在application.properties中配置一下thymeleaf使用html模板即可

# 使用html模板
spring.thymeleaf.mode=HTML
# 编译缓存,开发环境写false,更新页面可马上看到效果;生产环境用true,速度快一些,但更新页面后需重启应用才能看到效果
spring.thymeleaf.cache=false

关于使用thymeleaf-extras-springsecurity扩展,需要单独写配置类配置,那是本文重点,后边会有描述。

Spring security集成

首先引入spring security的依赖

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

要使用spring security,还需要手工做一下配置,这里是一个简单的基本配置

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.bu
8000
ilders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

//将密码写在application.properties文件里边,并在配置类中读取
@Value("${app.admin.password}")
private String adminPassword;

@Override
protected void configure(HttpSecurity http) throws Exception {
//配置一些静态地址的访问路径不通过权限验证,以及登入及登出的配置
http
.authorizeRequests()
.antMatchers("/themes/**", "/assets/**", "/components/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//简单的配置了使用内存的验证方式,固定一个用户名和密码
auth
.inMemoryAuthentication()
.withUser("admin").password(adminPassword).roles("ADMIN");
}

}


控制器及视图实现

然后再写一个负责登入登出的controller

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MyController {

//登入后的首页
@RequestMapping("/")
public ModelAndView homepage(HttpServletRequest request){
return new ModelAndView("index");
}

//登入地址,当访问任何需验证授权的资源时发现未登入,通过之前的security配置会自动跳转到该地址
@RequestMapping("/login")
public ModelAndView login(){
return new ModelAndView("login");
}

/**
* 登出处理
*/
@RequestMapping("/logout")
public ModelAndView logoutView(HttpServletRequest request, HttpServletResponse response){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}

return new ModelAndView("redirect:/");
}
}

然后是一个登入窗口页面,使用thymeleaf3的html模板

<!doctype html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" data-th-content="'登入 - '+${title}" content="">
<meta content="width=device-width, initial-scale=1, user-scalable=no" name="viewport">
<title data-th-text="'登入 - '+${title}">Login | APP NAME</title>
<link rel="shortcut icon" type="image/x-icon" href="" data-th-href="@{/themes/images/favicon.ico}">

<!-- Bootstrap css -->
<link rel="stylesheet" type="text/css" href="" data-th-href="@{/assets/css/bootstrap.min.css}">

</head>

<body class="body-custom">
<div class="logincard">
<div class="card-default">
<div class="login-card">
<form th:action="@{/login}" id="login-form" method="post">
<div class="text-center">
<div class="loginlogo">
<a href="javascript:void(0);"><img src="" alt="Logo" data-th-src="@{/themes/images/logo-icon.png}"></a>
</div>
<h3>登入 <span>到 <strong data-th-text="${title}">APP NAME</strong></span></h3>
</div>

<div class="pmd-card-body">
<div class="alert-danger" role="alert" data-th-if="${param.error}!=null">用户名或密码错误,请重新输入</div>
<div class="form-group">
<label for="inputError1" class="control-label">用户名</label>
<div class="input-group">
<div class="input-group-addon"><i class="material-icons md-dark">perm_identity</i></div>
<input type="text" name="username" class="form-control" id="exampleInputAmount">
</div>
</div>

<div class="form-group">
<label for="inputError1" class="control-label">密码</label>
<div class="input-group">
<div class="input-group-addon"><i class="material-icons md-dark">lock_outline</i></div>
<input type="password" name="password" class="form-control" id="exampleInputAmount">
</div>
</div>
</div>
<div class="text-center">
<a href="javascript:void(0);" id="login-button" type="button" class="btn btn-primary btn-block">登入</a>

</div>

</form>
</div>
</div>
</div>

<!-- Scripts Starts -->
<script src="" data-th-src="@{/assets/js/jquery-1.12.2.min.js}"></script>
<script src="" data-th-src="@{/assets/js/bootstrap.min.js}"></script>
<!-- login page sections show hide -->
<script type="text/javascript">
$(document).ready(function(){
$('#login-button').click(function(){
$('#login-form').submit()
})
});
</script>

<!-- Scripts Ends -->

</body>
</html>

然后登入后的页面,我们需要在页面显示登入者的名称

<!doctype html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" data-th-content="${title}" content="">
<meta content="width=device-width, initial-scale=1, user-scalable=no" name="viewport">

<title data-th-text="${title}"></title>
<link rel="shortcut icon" type="image/x-icon" href="" data-th-href="@{/themes/images/favicon.ico}">
<!-- Bootstrap css -->
<link rel="stylesheet" type="text/css" href="" data-th-href="@{/assets/css/bootstrap.min.css}" />
</head>

<body>
<div data-th-text="${#authentication.name}"></div>
<div><a href="" data-th-href="@{/logout}">登出</a></div>
</body>
</html>

我们这里使用data-th-text="${#authentication.name}"使div里边显示登入用户的名称

其中#authentication是指向了一个org.thymeleaf.extras.springsecurity4.auth.Authorization的对象实例(org.springframework.security.core.Authentication接口的实现),这里需要引入本文的重点:thymeleaf-extras-springsecurity扩展

thymeleaf-extras-springsecurity扩展是thymeleaf对spring security一个扩展模块,该模块提供一个新的dialect叫作org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect,增加该dialect后,可以在页面上用sec前缀获得很多来自spring security的内容

例如:

<div data-sec-authentication="name"></div>

也是可以在div内显示登入者的名称

更可以获取当前登入用户的角色,从而判断部分内容是否对其显示

<div data-sec-authorize="hasRole('ADMIN')">
这部分内容当用户角色为为ADMIN时显示
</div>

具体还可以做什么,可以到该项目的github上边看说明:https://github.com/thymeleaf/thymeleaf-extras-springsecurity

Thymeleaf-extras-springsecurity的扩展的集成

现在开始我们在这个项目上引入该扩展的依赖,如果你使用的是spring-security3,记得要改一下artifactId

<!-- thymeleaf的spring security扩展 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>${thymeleaf.version}</version>
</dependency>

再我们之前使用的security配置类里边加入这部分扩展的bean声明

@Bean
public SpringResourceTemplateResolver templateResolver(){
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
//配置模板
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
// 使用HTML的模式,也就是支持HTML5的方式,使用data-th-*的H5写法来写thymeleaf的标签语法
templateResolver.setTemplateMode(TemplateMode.HTML);
// 之前在application.properties中看到的缓存配置
templateResolver.setCacheable(true);

return templateResolver;
}

@Bean
public SpringTemplateEngine templateEngine() {
//模板引擎增加SpringSecurityDialect,让模板能用到sec前缀,获取spring security的内容
SpringTemplateEngine engine = new SpringTemplateEngine();
SpringSecurityDialect securityDialect = new SpringSecurityDialect();
Set<IDialect> dialects = new HashSet<>();
dialects.add(securityDialect);
engine.setAdditionalDialects(dialects);

engine.setTemplateResolver(templateResolver());
//允许在内容中使用spring EL表达式
engine.setEnableSpringELCompiler(true);

return engine;
}

//声明ViewResolver
@Bean
public ThymeleafViewResolver viewResolver(){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}

大功告成!

以上即是本文所有内容,也是工作中一些记录,希望对看到本文的您有所帮助,少走一些弯路

参考网址:
https://github.com/thymeleaf/thymeleaf-extras-springsecurity https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html http://www.thymeleaf.org/doc/articles/springsecurity.html https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息