Spring Security
Spring Security 是Spring 項目中用來提供安全認證服務的架構.
- 認證: 是為使用者建立一個他所聲明的主體, 主體一般指使用者, 裝置或可以在你系統中執行動作的其他系統.
- 授權: 指的是一個使用者能否在你的應用中執行某個操作, 在到達授權判斷之前, 身份的主體已經由身份驗證過程建立了.
這些概念是通用的, 不是Spring Security特有的, 在身份驗證層面, Spring Security廣泛支援各種身份驗證模式.
入門
導入依賴坐标
<!-- spring-security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
web.xml配置
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
Spring-Security.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<security:http auto-config="true" use-expressions="false">
<!--
intercept-url 定義一個過濾規則 pattern表示對哪些url進行權限控制. access熟悉表示在請求對于的yrl時需要什麼權限
預設配置時它應該是一個已逗号分隔的角色清單, 請求的使用者隻需擁有其中的一個角色就能成功通路對應的URL
-->
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<!--
auto-config 配置後, 不需要在配置下面資訊 <security:from-login/>定義登入表單資訊
<security:http-basic/> <security:logout/>
-->
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="user" password="{noop}user" authorities="ROLE_USER"/>
<security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
指定資源不過濾
<!-- 配置不過濾的資源(靜态資源及登入相關) -->
<security:http security="none" pattern="/login.html" />
<security:http security="none" pattern="/failer.html" />
指定登入頁面(成功, 失敗, 登出)
<security:http auto-config="true" use-expressions="false" >
<!-- 配置資料連接配接,表示任意路徑都需要ROLE_USER權限 -->
<security:intercept-url pattern="/**" access="ROLE_USER" />
<!--
自定義登陸頁面,login-page 自定義登陸頁面 authentication-failure-url 使用者權限校驗失敗之後才會跳轉到這個頁面,如果資料庫中沒有這個使用者則不會跳轉到這個頁面。
default-target-url 登陸成功後跳轉的頁面。 注:登陸頁面使用者名固定 username,密碼 password,action:login
-->
<security:form-login login-page="/login.html" login-processing-url="/login" username-parameter="username" password-parameter="password" authentication-failure-url="/failer.html" default-target-url="/success.html" authentication-success-forward-url="/success.html"/>
<!--
登出, invalidate-session 是否删除session logout-url:登出處理連結 logout-success-url:登出成功頁面
注:登出操作 隻需要連結到 logout即可登出目前使用者
-->
<security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.jsp" />
<!-- 關閉CSRF,預設是開啟的 -->
<security:csrf disabled="true" />
</security:http>
UserDetails
UserDetails
UserDetails
是一個接口, 對認證主體進行了規範, 通常使用實作類
User
進行使用
其中
Collection<? extends GrantedAuthority>
代表了角色擁有的權限集合, 其集合繼承了
GrantedAuthority
public interface UserDetails extends AuthenticatedPrincipal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
default String getName() {
return this.getUsername();
}
}
UserDetallService
UserDetallService
IUserService
需要繼承
UserDetailsService
類
public interface IUserService extends UserDetailsService {
}
UserServiceImpl
需要實作
loadUserByUsername
方法, 傳回值為
UserDetails
, 使用實作類
User
傳回
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
userInfo = dao.findByUsername(s);
} catch (Exception e) {
e.printStackTrace();
}
assert userInfo != null;
//處理自己的使用者對象封裝成UserDetails
return new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(), userInfo.getStatus() == 1, true, true, true, getAuthority(userInfo.getRoles()));
}
構造
User
實體需要傳入角色的權限集合, 即
Collection<? extends GrantedAuthority>
, 是以提供了一個私有方法來擷取權限的集合, 集合的類型為
SimpleGrantedAuthority
其繼承了
GrantedAuthority
.
/**
* 傳回一個list集合, 集合中裝入的是角色描述
* @return list集合
*/
private List<SimpleGrantedAuthority> getAuthority(List<Role> roles){
List<SimpleGrantedAuthority> list = new ArrayList<>();
for (Role role : roles) {
list.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
}
return list;
}
完整代碼實作:
/**
* @Author Harlan
* @Date 2020/9/25
*/
@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao dao;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
userInfo = dao.findByUsername(s);
} catch (Exception e) {
e.printStackTrace();
}
assert userInfo != null;
//處理自己的使用者對象封裝成UserDetails
return new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(), userInfo.getStatus() == 1, true, true, true, getAuthority(userInfo.getRoles()));
}
/**
* 傳回一個list集合, 集合中裝入的是角色描述
* @return list集合
*/
private List<SimpleGrantedAuthority> getAuthority(List<Role> roles){
List<SimpleGrantedAuthority> list = new ArrayList<>();
for (Role role : roles) {
list.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
}
return list;
}
}