Spring Security 提供多种认证方式:
HTTP BASIC authentication headers (一个基于 IEFT RFC 的标准)
HTTP Digest authentication headers (一个基于 IEFT RFC 的标准)
HTTP X.509 client certificate exchange (一个基于 IEFT RFC 的标准)
LDAP (一个非常常见的跨平台认证需要做法,特别是在大环境)
Form-based authentication (提供简单用户接口的需求)
OpenID authentication
基于预先建立的请求头进行认证 (比如 Computer Associates Siteminder)
JA-SIG Central Authentication Service (也被称为 CAS,这是一个流行的
开源单点登录系统)
Transparent authentication context propagation for Remote Method
Invocation (RMI) and HttpInvoker (一个 Spring 远程调用协议)
Automatic “remember-me” authentication (这样你可以设置一段时间,避
免在一段时间内还需要重新验证)
Anonymous authentication (允许任何调用,自动假设一个特定的安全主体)
Run-as authentication (这在一个会话内使用不同安全身份的时候是非常有 用的)
Java Authentication and Authorization Service (JAAS)
JEE Container autentication (这样,你可以继续使用容器管理认证,如果想
的话)
Kerberos
Java Open Source Single Sign On (JOSSO) *
OpenNMS Network Management Platform *
AppFuse *
AndroMDA *
Mule ESB *
Direct Web Request (DWR) *
Grails *
Tapestry *
JTrac *
Jasypt *
Roller *
Elastic Plath *
Atlassian Crowd *
。。。。。
本示例以表单登录为例,来演示自定义表单登录:
1. 使用版本及工具
Spring Boot 1.5.9.RELEASE
JDK1.8
Maven 3
Eclipse
MySQL
2. 示例结构
3. 定义用户信息和权限
通过实现 UserDetails 借口来定义用户表,UserInfo.java 用以存储用户基本信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| package com.devnp.springbootsecurityformlogindemo.entity;
import java.util.ArrayList; import java.util.Collection; import java.util.List;
import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails;
@Entity @Table(name="user_info") public class UserInfo implements UserDetails {
private static final long serialVersionUID = 1L; @Id @GeneratedValue private Long id ; @Column(name="user_name", length=30) private String userName ; @Column(name="password", length=256) private String password ; @OneToMany(fetch = FetchType.EAGER, mappedBy="userInfo", cascade=CascadeType.ALL) private List<UserRole> userRoles = new ArrayList<>();
@Override public Collection<? extends GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); for (UserRole userRole : userRoles) { authorities.add(new SimpleGrantedAuthority(userRole.getSysRole().getRoleName())); } return authorities; }
@Override public String getPassword() { return this.password; }
@Override public String getUsername() { return this.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 Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public void setPassword(String password) { this.password = password; } }
|
SysRole.java 系统角色权限
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package com.devnp.springbootsecurityformlogindemo.entity;
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table;
@Entity @Table(name="sys_role") public class SysRole {
@Id @GeneratedValue @Column(name="role_id") private Long roleId; @Column(name="role_name", length=30) private String roleName ;
public SysRole() { super(); }
public SysRole(Long roleId, String roleName) { super(); this.roleId = roleId; this.roleName = roleName; }
public Long getRoleId() { return roleId; }
public void setRoleId(Long roleId) { this.roleId = roleId; }
public String getRoleName() { return roleName; }
public void setRoleName(String roleName) { this.roleName = roleName; } }
|
UserRole.java 用户具有的角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| package com.devnp.springbootsecurityformlogindemo.entity;
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
@Entity @Table(name="user_role") public class UserRole { @Id @GeneratedValue @Column(name="id") private Long id; @JsonIgnore @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) private UserInfo userInfo ;
@JsonIgnore @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "role_id", nullable = false) private SysRole sysRole ;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public UserInfo getUserInfo() { return userInfo; }
public void setUserInfo(UserInfo userInfo) { this.userInfo = userInfo; }
public SysRole getSysRole() { return sysRole; }
public void setSysRole(SysRole sysRole) { this.sysRole = sysRole; } }
|
4. UserDetailsService
在Spring Security 中 通过实现 UserDetailsService 接口来完成对自定义用户信息的查找:
UserInfoService.java
1 2 3 4 5 6 7 8 9 10 11
| package com.devnp.springbootsecurityformlogindemo.service;
import org.springframework.security.core.userdetails.UserDetailsService;
public interface UserInfoService extends UserDetailsService{
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.devnp.springbootsecurityformlogindemo.service;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service;
import com.devnp.springbootsecurityformlogindemo.repository.UserInfoRepository;
@Service public class UserInfoServiceInpl implements UserInfoService {
@Autowired private UserInfoRepository userInfoRepository;
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userInfoRepository.findByUserName(username); }
}
|
5. Repository
UserInfoRepository.java 同过Spring JPA 来完成查找:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.devnp.springbootsecurityformlogindemo.repository;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository;
import com.devnp.springbootsecurityformlogindemo.entity.UserInfo;
@Repository public interface UserInfoRepository extends JpaRepository<UserInfo, Long> {
UserInfo findByUserName(String userName); }
|
6. 配置
首先对表单登录的配置:
1.指定表单登录
2.设置登录的URL/页面
3.设置登录发送的URL
4.以及对登录成功后处理和跳转
5.配置“/”为不需要登录验证
6.设置其他请求都需要授权
SecurityFormLoginConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package com.devnp.springbootsecurityformlogindemo.config;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration public class SecurityFormLoginConfig extends WebSecurityConfigurerAdapter{
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/") .loginProcessingUrl("/login") .and() .authorizeRequests().antMatchers("/").permitAll() .and() .authorizeRequests() .anyRequest().authenticated() .and() .csrf().disable(); }
}
|
对系统常用配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server: context-path: /boot-form-login
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8 username: root password: "!qaz2wsx" jpa: hibernate: ddl-auto: update show-sql: true
|
7. 登录页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>Login Form</title> </head> <body> <form action="login" method="POST"> <div> <div> <label>用户名:</label><input type="text" name="username" /> </div> <div> <label>密 码:</label><input name="password" type="password"/> </div> </div> <div> <button type="submit">登陆</button> </div> </form> </body> </html>
|
8. 控制器
其控制器主要包括跳转登录页面,以及访问登录者信息:
IndexController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.devnp.springbootsecurityformlogindemo.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;
@Controller public class IndexController {
@RequestMapping("/") public String index() { return "login-form" ; } @RequestMapping("/index") @ResponseBody public Object welcome(@Autowired Authentication authentication) { return authentication ; } }
|
9. 测试
可以同过执行如下SQL来插入一个用户:
1 2 3
| insert into user_info (user_name, password) values ('duliu','$2a$10$MraEjVZI8V8v4gsykjjFxeRxZa.HiNIsPtueOLXb0ekuegSRDyW26') ; insert into sys_role (role_name) values ('admin') ; insert into user_role (user_id, role_id) values (1,1) ;
|
访问 http://localhost:8080/boot-form-login/index 跳转到登录页面:
输入用户名 和 密码 登录:
10. 代码下载
spring-boot-security-form-login-demo.zip
Author:
Darren Du
License:
Copyright (c) 2019 MIT LICENSE