具体Demo目录:
User类为认证和授权实体类,
Role类为用户角色类,有ROLE_ADMIN和ROLE_USER
User:
package com.example.demo.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;
/**
* Created by linziyu on 2018/5/13.
* 用户实体类,通过实现UserDetails接口实现认证及授权
*/
@Entity
@Table(name = "user1") //设置对应表名字
public class User implements UserDetails{
//主键及自动增长
@Id
@GeneratedValue
private long id;
private String name;
private String password;
//多对多映射,用户角色
@ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
private List roles;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getRoles() {
return roles;
}
public void setRoles(List roles) {
this.roles = roles;
}
//获取当前用户实例的password
@Override
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public User(String name, String password) {
this.name = name;
this.password = password;
}
public User() {
}
//根据自定义逻辑来返回用户权限,如果用户权限返回空或者和拦截路径对应权限不同,验证不通过
@Override
public Collection extends GrantedAuthority> getAuthorities() {
List authorities = new ArrayList<>();
List roles = this.getRoles();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getRolename()));
}
return authorities;
}
//获取当前用户实例的name
@Override
public String getUsername() {
return this.name;
}
//帐号是否不过期,false则验证不通过
@Override
public boolean isAccountNonExpired() {
return true;
}
//帐号是否不锁定,false则验证不通过
@Override
public boolean isAccountNonLocked() {
return true;
}
//凭证是否不过期,false则验证不通过
@Override
public boolean isCredentialsNonExpired() {
return true;
}
//该帐号是否启用,false则验证不通过
@Override
public boolean isEnabled() {
return true;
}
}
Role类:
package com.example.demo.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Created by linziyu on 2018/5/13
*
* 角色实体类
*
*/
@Entity
@Table(name = "role1")
public class Role {
@Id
@GeneratedValue
private long id;
private String rolename;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRolename() {
return rolename;
}
public void setRolename(String rolename) {
this.rolename = rolename;
}
}
使用的框架为Spring Data Jpa,所有只需继承JpaRepository即可。
安全配置:
package com.example.demo.config;
import com.example.demo.service.SecurityService;
import com.example.demo.util.MD5Util;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* Created by linziyu on 2018/5/13.
* 安全配置类
*
*/
@Configuration//指定为配置类
@EnableWebSecurity//指定为Spring Security配置类
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Bean
UserDetailsService Service(){
return new SecurityService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(Service()).passwordEncoder(new PasswordEncoder() {
//用户加密配置
@Override
public String encode(CharSequence charSequence) {
return MD5Util.encode((String)charSequence);
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(MD5Util.encode((String)charSequence));
}
});
}
/*
通过 authorizeRequests() 定义哪些URL需要被保护、哪些不需要被保护
通过 formLogin() 定义当需要用户登录时候,转到的登录页面。
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().
//设置静态资源均可以访问
antMatchers("/css/**", "/js/**","/images/**", "/webjars/**", "**/favicon.ico", "/index").permitAll()
.anyRequest().authenticated().
and().
//指定登录认证的Controller
formLogin().loginPage("/login").permitAll().
and().
logout().permitAll();
}
}
视图配置类:
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Created by linziyu on 2018/5/13.
* 视图跳转配置类
*
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//设置登录处理操作
registry.addViewController("/login").setViewName("login");
}
}
package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
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;
import org.springframework.stereotype.Service;
/**
* Created by linziyu on 2018/5/13.
* 加载用户特定数据类,为认证用户服务
*
*/
//@Service
public class SecurityService implements UserDetailsService{
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userRepository.findByName(s);
if (user == null) {
throw new UsernameNotFoundException("");
}
return user;
}
}
package com.example.demo.service;
import com.example.demo.entity.User;
import org.springframework.data.domain.Page;
/**
* Created by linziyu on 2018/5/13.
* 用户类Service
*
*/
public interface UserService {
void save(User user);//保存用户
}
package com.example.demo.util;
import java.security.MessageDigest;
/**
* Created by linziyu on 2018/5/15
*MD5加密工具
* .
*/
public class MD5Util {
private static final String SALT = "tamboo";
public static String encode(String password) {
password = password + SALT;
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
throw new RuntimeException(e);
}
char[] charArray = password.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
}
在前端使用了Thymeleaf进行渲染,特使是结合Spring Security在前端获取用户信息,如主页
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8"/>
<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">
ul>
div>
div>
nav>
<div class="container">
<div class="starter-template">
<div sec:authorize="isAuthenticated()">
<p>Hellop>
<p>你已登录p>
<p>登录名:<span sec:authentication="name">span>p>
<p>拥有的角色:
<span sec:authorize="hasRole('ROLE_ADMIN')">管理员span>
<span sec:authorize="hasRole('ROLE_USER')">普通用户span>
p>
div>
<form th:action="@{/logout}" method="post">
<input type="submit" class="btn btn-primary" value="Logout"/>
form>
<div sec:authorize="hasRole('ROLE_ADMIN')">
<form th:action="@{/toAddUser}" method="post">
<input type="submit" class="btn btn-primary" value="Create"/>
form>
div>
div>
div>
body>
html>
要注意两点:
1 依赖添加
<dependency>
<groupId>org.thymeleaf.extrasgroupId>
<artifactId>thymeleaf-extras-springsecurity4artifactId>
dependency>
2 版本要求
需要保持thymeleaf-extras-springsecurity4 版本与 thymeleaf相同
这样才能在前端使用类似于这种语句来获取登录用户信息
具体语法可查看:
https://github.com/thymeleaf/thymeleaf-extras-springsecurity
我的整个Demo在我的GitHub上:
https://github.com/LinZiYU1996/Spring-Boot-Spring-Security