一,Spring Security快速入门
1,什么是Spring Security
Spring Security是专门针对基于Spring的项目的安全框架,充分利用了依赖注入和AOP来实现安全的功能。
在早期的Spring Security版本,使用Spring Security需要使用大量的xml配置,而下面将全部基于Java配置来实现Spring Security的功能。
安全框架有两个重要的概念,即认证(Authentication)和授权(Authorization)。认证即确认用户可以访问当前系统;授权即确定用户在当前系统下所拥有的功能权限,下面将围绕认证和授权展开。
2,Spring Security的配置
1)DelegatingFilterProxy
Spring Security为我们提供了一个多个过滤器来实现所有安全的功能,我们只需注册一个特殊的DelegatingFilterProxy过滤器到WebAppliactionInitializer即可。
而在实际使用中,我们只需让自己的Initializer类继承AbstractSecurityWebApplicationInitializer抽象类即可。AbstractSecurityWebApplicationInitializer实现了WebApplicationInitializer接口,并通过onStartup方法调用:
insertSpringSecurityFilterChain(servletContext);
它为我们注册了DelegatingFilterProxy。insertSpringSecurityFilterChain源码如下:
private void insertSpringSecurityFilterChain(ServletContext servletContext) {
String filterName = "springSecurityFilterChain";
DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(filterName);
String contextAttribute = this.getWebApplicationContextAttribute();
if (contextAttribute != null) {
springSecurityFilterChain.setContextAttribute(contextAttribute);
}
this.registerFilter(servletContext, true, filterName, springSecurityFilterChain);
}
所以我们只需要用以下代码即可开启Spring Security的过滤器支持:
package com.jack.springboot12springsecurit.controller;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
/**
* create by jack 2017/10/12
*/
public class AppInitializer extends AbstractSecurityWebApplicationInitializer{
}
2)配置
Spring Security的配置和Spring MVC的配置类似,只需在一个配置类上注解@EnableWebSecurity,并让这个类继承WebSecurityConfigurerAdapter即可。我们可以通过重写configure方法来配置相关的安全配置。代码如下:
package com.jack.springboot12springsecurit.config;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* create by jack 2017/10/12
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
}
}
3,用户认证
认证需要我们有一套用户数据的来源,而授权则是对于某个用户有相应的角色权限。在Spring Security里我们通过重写
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
}
方法来实现。
1)内存中的用户
使用AuthenticationManagerBuilder的inMemoryAuthentication方法即可添加在内存中的用户,并可给用户指定角色权限。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//super.configure(auth);
auth.inMemoryAuthentication()
.withUser("jack1").password("jack1").roles("ROLE_ADMIN")
.and()
.withUser("jack2").password("jack2").roles("ROLE_USER");
}
2)JDBC中的用户
JDBC中的用户之间指定dataSource即可。
package com.jack.springboot12springsecurit.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import javax.sql.DataSource;
/**
* create by jack 2017/10/12
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//super.configure(auth);
auth.jdbcAuthentication().dataSource(dataSource);
}
}
不过这看上去很奇怪,其实这里的Spring Security是默认了你的数据库结构的。通过jdbcAuthentication的源码,我们可以看出在JdbcDaoImpl中定义了默认的用户及角色权限获取的sql语句:
public static final String DEF_USERS_BY_USERNAME_QUERY = "select username,password,enabled from users where username = ?"; public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY = "select username,authority from authorities where username = ?";
public static final String DEF_USERS_BY_USERNAME_QUERY = "select username,password,enabled from users where username = ?";
public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY = "select username,authority from authorities where username = ?";
当然我们可以自定义我们的查询用户和权限的sql语句,例如:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//super.configure(auth);
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select username,password,true "
+ "from myusers where username = ?")
.authoritiesByUsernameQuery("select username,role "
+" from roles where username = ?");
}
3)通用的用户
上面的两种用户和权限的获取方式只限于内存或者jdbc,我们的数据访问方式可以是各种各样的,可以是非关系型数据库,也可以是我们常用的JPA等。
这时我们需要自定义实现UserDetailsService接口。上面的内存中用户及JDBC用户就是UserDetailsService的实现,定义如下:
package com.jack.springboot12springsecurit.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.ArrayList;
import java.util.List;
/**
* create by jack 2017/10/12
*/
public class CustomUserService implements UserDetailsService{
@Autowired
SysUserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser user= userRepository.findByUserName(username);
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new User(user.getUsername(),user.getPassword(),authorities);
}
}
说明:SysUser是我们系统的用户领域对象类,User来自于org.springframework.security.core.userdetails.User.
除此之外,我们还需要注册这个CustomUserService,代码如下:
@Bean
UserDetailsService customUserService(){
return new CustomUserService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService());
}
4,请求授权
Spring Security是通过重写
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
方法来实现请求拦截的。
Spring Security使用以下匹配器来匹配请求路径:
antMatchers:使用Ant风格的路径匹配。
regexMatchers:使用正则表达式匹配路径
anyRequest:匹配所有请求路径。
在匹配了请求路径后,需要针对当前用户的信息对请求路径进行安全处理,Spring Security提供了下面的安全处理方法:
access(String) :Spring EL表达式结构为true时可访问
anonymous():匿名可访问
denyAll():用户不能访问
fullyAuthenticated():用户完全认证可访问(非remember me下自动登入)
hasAnyAuthority(String...):如果用户有参数,则其中任一权限可访问
hasAnyRole(String...):如果用户有参数,则其中任一角色可访问
hasAuthority(String):如果用户有参数,则其权限可访问
hasIpAddress(String):如果用户来自参数中的ip则可访问
hasRole(String):若用户有参数中的角色可访问
permitAll():用户可任意访问
rememberMe():允许通过remember-me登录的用户访问
authenticated():用户登录后可访问
我们可以看一下下面的示例代码:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()//通过authorizeRequests方法来开始请求权限配置
.antMatchers("/admin/**").hasRole("ROLE_ADMIN")//请求匹配/admin/**,只有ROLE_ADMIN角色的用户可访问
.antMatchers("/user/**").hasAnyRole("ROLE_ADMIN","ROLE_USER")//请求匹配/user/**,拥有ROLE_ADMIN或ROLE_USER角色的用户都可访问
.anyRequest().authenticated();//其余所有的请求都需要认证后(登入后)才可访问
}
5,定制登入行为
我们也可以通过重写
protected void configure(HttpSecurity http)
方法来定制我们的登入行为。
下面将重用的登入行为的定制以简短的代码演示:
@Override
protected void configure(HttpSecurity http) throws Exception {
/*http
.authorizeRequests()//通过authorizeRequests方法来开始请求权限配置
.antMatchers("/admin/**").hasRole("ROLE_ADMIN")//请求匹配/admin/**,只有ROLE_ADMIN角色的用户可访问
.antMatchers("/user/**").hasAnyRole("ROLE_ADMIN","ROLE_USER")//请求匹配/user/**,拥有ROLE_ADMIN或ROLE_USER角色的用户都可访问
.anyRequest().authenticated();//其余所有的请求都需要认证后(登入后)才可访问*/
http
.formLogin()//通过formLogin方法定制登录操作
.loginPage("/login")//使用loginPage方法定制登入页面的访问地址
.defaultSuccessUrl("/index")//defaultSuccessUrl指定登入成功后转向的页面
.failureUrl("/login?error")//failureUrl指定登入失败后转向的页面
.permitAll()
.and()
.rememberMe()//rememberMe开启cookie存储用户信息
.tokenValiditySeconds(1209600)//tokenValiditySeconds指定cookie有效期为1209600秒,即两个星期
.key("myKey")//指定cookie中的私钥
.and()
.logout()//使用logout方法定制注销行为
.logoutUrl("/custom-logout")//logoutUrl指定注销的URL路径
.logoutSuccessUrl("/logout-success")//logoutSuccessUrl指定注销成功后转向的页面
.permitAll();
}
二,Spring Boot的支持
Spring Boot针对Spring Security的自动配置在org.springframework.boot.autoconfigure.security包中。
主要通过SecurityAutoConfiguration和SecurityProperties来完成配置。
SecurityAutoConfiguration导入SpringBootWebSecurityConfiguration中配置。在SpringBootWebSecurityConfiguration配置中,我们获得如下的自动配置:
1)自动配置了一个内存中的用户,账号为user,密码在程序启动时出现
2)忽略/css/**,/js/**,/images/**和/**/favicon.ico等静态文件的拦截。
3)自动配置的securityFilterChainRegistration的Bean.
SecurityProperties使用“security”为前缀的属性配置Spring Security相关的配置,包含:
#内存中的用户默认账号为uer
security.user.name=user
#1默认用户的密码
security.user.password=
#默认用户的角色
security.user.role=USER
#是否需要ssl支持
security.require-ssl=false
#是否开启“跨战请求伪造”支持,默认关闭
security.enable-csrf=false
security.basic.enabled=true
security.basic.realm=Spring
# /**
security.basic.path=
security.basic.authorize-mode=
security.filter-order=0
security.headers.xss=true
security.headers.cache=true
security.headers.frame=true
security.headers.content-type=false
security.headers.hsts=all
security.sessions=stateless
#用逗号隔开的无须拦截的路径
security.ignored=
Spring Boot为我们做了如此多的配置,当我们需要自己扩展的配置时,只需配置类继承WebSecurityConfigurerAdapter类即可,无须使用@EnableWebSecurity注解,例如:
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{}
三,实战
下面的示例中,演示使用Spring Boot下的Spring Security的配置,完成简单的认证授权的功能。下面我们将通过Spring Data JPA获得用户数据。页面模板使用Thymeleaf,Thymeleaf也为我们提供了支持Spring Security的标签。
1,新建Spring Boot项目
新建Spring Boot项目,依赖JPA,Security,Thymeleaf,mysql驱动
pom.xml代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jack</groupId>
<artifactId>springboot12springsecurit</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot12springsecurit</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
<!--mysql连接驱动-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.39</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties如下:
server.port=9090
spring.datasource.data-username=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jack
spring.datasource.username=root
spring.datasource.password=root
logging.level.org.springframework.security=INFO
spring.thymeleaf.cache=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
将bootstrap.min.css放置在src/main/resources/static/css下,此路径默认不拦截
2,用户和角色
我们使用JPA来定义用户和角色
用户:
package com.jack.springboot12springsecurit.entity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* create by jack 2017/10/18
*/
/**
* 让我们的用户实体实现UserDetailsService接口,我们的用户实体即为Spring Security所使用的用户
*/
@Entity
public class SysUser implements UserDetails{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue//(strategy= GenerationType.AUTO)
private Integer id;
private String username;
private String password;
/**
* 配置用户和角色的多对多关心
*/
@ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
private List<SysRole> roles;
public static long getSerialVersionUID() {
return serialVersionUID;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public void setUsername(String username) {
this.username = username;
}
/**
* 重写getAuthorities方法,将用户的角色作为权限
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> auths = new ArrayList<>();
List<SysRole> roles = this.roles;
for (SysRole role:
roles) {
auths.add(new SimpleGrantedAuthority(role.getName()));
}
return auths;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<SysRole> getRoles() {
return roles;
}
public void setRoles(List<SysRole> roles) {
this.roles = roles;
}
}
角色:
package com.jack.springboot12springsecurit.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* create by jack 2017/10/18
*/
@Entity
public class SysRole {
@Id
@GeneratedValue//(strategy= GenerationType.AUTO)
private Integer id;
//角色名称
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
1)数据结构及初始化
当我们配置用户和角色的多对多关心后,通过设置:
spring.jpa.hibernate.ddl-auto=update
为我们自动生成用户表:sys_user,角色表:sys_role,关联表:sys_user_roles.
针对上面的结构,我们初始化一些数据来方便我们演示。在src/main/resources下,新建data.sql,即新建两个用户,角色分别为role_admin和role_user,代码如下:
INSERT INTO sys_user(id,username,password) VALUES (1,'jack1','jack1');
INSERT INTO sys_user(id,username,password) VALUES (2,'jack2','jack2');
INSERT INTO sys_role(id,name) VALUES (1,'ROLE_ADMIN');
INSERT INTO sys_role(id,name) VALUES (2,'ROLE_USER');
INSERT INTO sys_user_roles(sys_user_id,roles_id) VALUES (1,1);
INSERT INTO sys_user_roles(sys_user_id,roles_id) VALUES (2,2);
2)传值对象
用来测试不同角色用户的数据展示:、
package com.jack.springboot12springsecurit.pojo;
/**
* create by jack 2017/10/18
*/
public class Msg {
private String title;
private String content;
private String etraInfo;
public Msg(String title, String content, String etraInfo) {
super();
this.title = title;
this.content = content;
this.etraInfo = etraInfo;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getEtraInfo() {
return etraInfo;
}
public void setEtraInfo(String etraInfo) {
this.etraInfo = etraInfo;
}
}
3,数据访问
我们这里的数据访问很简单,代码如下:
package com.jack.springboot12springsecurit.dao;
import com.jack.springboot12springsecurit.entity.SysUser;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* create by jack 2017/10/18
*/
public interface SysUserRepository extends JpaRepository<SysUser,Integer> {
SysUser findByUsername(String username);
}
上面一个方法是根据用户名查询出用户
4,自定义UserDetailsService
package com.jack.springboot12springsecurit.service;
import com.jack.springboot12springsecurit.dao.SysUserRepository;
import com.jack.springboot12springsecurit.entity.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
* create by jack 2017/10/18
*/
/**
* 自定义需实现UserDetailsService接口
*/
public class CustomUserService implements UserDetailsService{
@Autowired
private SysUserRepository userRepository;
/**
* 重写loadUserByUsername方法获得用户
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
//我们当前的用户实现了UserDetails接口,可直接返回给Spring Security使用
return user;
}
}
5,配置
1)Spring MVC配置
package com.jack.springboot12springsecurit.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* create by jack 2017/10/18
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//super.addViewControllers(registry);
registry.addViewController("/login").setViewName("login");
}
}
注册访问/login转向login.html页面
2)Spring Security配置
package com.jack.springboot12springsecurit.config;
import com.jack.springboot12springsecurit.service.CustomUserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.UserDetailsService;
/**
* create by jack 2017/10/18
*/
/**
* 扩展Spring Security配置需要继承WebSecurityConfigurerAdapter
*/
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
/**
* 注册CustomUserService的Bean
* @return
*/
@Bean
UserDetailsService customUserService(){
return new CustomUserService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//super.configure(auth);
/**
* 添加我们自定义的user detail service认证
*/
auth.userDetailsService(customUserService());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(http);
http.authorizeRequests()
.anyRequest()
.authenticated()//所有请求需要认证即登入后才能访问
.and()
.formLogin()
.loginPage("/login")
.successForwardUrl("/security/index")//登入成功后的跳转路径
.failureUrl("/login?error")
.permitAll()//定制登入行为,登入页面可任意访问
.and()
.logout()
.permitAll();//定制注销行为,注销请求可任意访问
}
}
6,页面
1)登录页面login.html,代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html;charset=UTF-8"/>
<title>security登入页面</title>
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
<style type="text/css">
body {
padding-top: 50px;
}
.starter-template {
padding: 40px 15px;
text-align: center;
}
</style>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">spring security演示</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a th:href="@{/}">首页</a></li>
</ul>
</div><!--/.nav-collapse-->
</div>
</nav>
<div class="container">
<div class="starter-template">
<!--注销成功后显示-->
<p th:if="${param.logout}" class="bg-warning">已成功注销</p>
<!--登入有错误时显示-->
<p th:if="${param.error}" class="bg-danger">有错误,请重试</p>
<h2>使用账户密码登入</h2>
<!--默认的登入路径为/login(自Spring Security4.x开始)-->
<form name="form" th:action="@{/login}" action="/login" method="post">
<div class="form-group">
<label for="username">账户</label>
<input type="text" class="form-control" name="username" value="" placeholder="账户"/>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" name="password" placeholder="密码"/>
</div>
<input type="submit" id="login" value="Login" class="btn btn-primary"/>
</form>
</div>
</div>
</body>
</html>
2)主页,home.html代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<!--xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
是thymeleaf为我们提供的spring security的标签支持-->
<head>
<meta content="text/html;charset=UTF-8"/>
<!--通过sec:authentication="name"获得当前用户的用户名-->
<title sec:authentication="name"></title>
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
<style type="text/css">
body {
padding-top: 50px;
}
.starter-template {
padding: 40px 15px;
text-align: center;
}
</style>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">spring security演示</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a th:href="@{/}">首页</a></li>
</ul>
</div><!--/.nav-collapse-->
</div>
</nav>
<div class="container">
<div class="starter-template">
<h1 th:text="${msg.title}"></h1>
<p class="bg-primary" th:text="${msg.content}"></p>
<!--sec:authentication="hasRole('ROLE_ADMIN')"意味着只有当前用户觉得为ROLE_ADMIN时
,才可显示标签内容-->
<div sec:authorize="hasRole('ROLE_ADMIN')">
<p class="bg-info" th:text="${msg.etraInfo}"></p>
</div>
<!--sec:authentication="hasRole('ROLE_USER')"意味着只有当前用户觉得为ROLE_USER时,才可
显示标签内容-->
<div sec:authorize="hasRole('ROLE_USER')">
<p class="bg-info">无更多信息显示</p>
</div>
<form th:action="@{/logout}" method="post">
<!--注销的默认路径为/logout,需通过post请求提交-->
<input type="submit" class="btn btn-primary" value="注销"/>
</form>
</div>
</div>
</body>
</html>
7,控制器
此控制器很简单,只为首页显示准备数据:
package com.jack.springboot12springsecurit.controller;
import com.jack.springboot12springsecurit.pojo.Msg;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* create by jack 2017/10/18
*/
@Controller
@RequestMapping("security")
public class SecurityController {
@RequestMapping("/index")
//@RequestMapping("/")
public String index(Model model){
Msg msg = new Msg("测试标题", "测试内容", "额外信息,只对管理员显示");
model.addAttribute("msg", msg);
return "home";
}
}
8,运行
1)登入。访问http://localhost:9090/login,将会自动转到登录页面http://localhost:9090/login,如下:
使用正确的账号密码登录:
1,使用role_admin的用户进行登录:
使用错误的账号登录:
2)注销。登入成功后,点击注销按钮如下:
3)用户信息
页面上我们将用户名显示在页面的标题上,如下:
用jack1和jack2用户名登入,对应的角色不同,上面显示的视图也不一样。
源代码地址:https://github.com/wj903829182/SpringCloudTwo/tree/master/springboot12springsecurit