SpringBoot+Spring security+Mysql
阿新 • • 發佈:2020-12-31
技術標籤:# Sprng Security
這裡寫自定義目錄標題
- 1.匯入pom配置檔案
- 2.配置全域性配置檔案(application.properties)
- 3.啟動類:HandWeb.java
- 4.配置Security的介面卡
- 5.書寫SQL語句
- 6.資料表構造
- 7.表資料展示
---------------承上啟下線------------
1.匯入pom配置檔案
< 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>2020</groupId>
< artifactId>HandlerInterceptor</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>HandlerInterceptor</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding >
</properties>
<!-- 管理bean -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jsp介面jstl依賴(下拉選擇) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- servlet 依賴 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!--使jsp頁面生效,進行訪問 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- spring-boot-starter-security依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 啟動shiro -->
<!-- <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0</version>
</dependency> -->
<!-- 整合Thymeleaf -->
<!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> -->
<!--通用mapper,tk.mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.1.4</version>
</dependency>
<!--對資料庫的支援 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--資料庫mysql的支援 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--json的支援 -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<!-- @Data依賴 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
</dependencies>
<build>
<finalName>HandlerInterceptor</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<!-- 設定編碼為 UTF-8 -->
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.配置全域性配置檔案(application.properties)
#jsp頁面處理
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
#MYSQL資料庫連線
spring.jpa.database = MYSQL
spring.datasource.url = jdbc:mysql://localhost/hand?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
spring.datasource.username =賬號
spring.datasource.password =密碼
#spring.datasource.password =密碼
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.initial-size=1
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.stat-view-servlet.allow=true
mybatis.typeAliasesPackage=com.hand.pojo
mybatis.mapperLocations=classpath:mappers/*.xml
mybatis.configuration.mapUnderscoreToCamelCase=true
mybatis.configuration.cacheEnabled=false
3.啟動類:HandWeb.java
package com.hand.web;
import org.mybatis.spring.annotation.MapperScan;
//import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@ComponentScan("com.hand")
@MapperScan("com.hand.mapper")
@EnableTransactionManagement//開啟事務---可以不寫
public class HandWeb {
public static void main(String[] args) {
SpringApplication.run(HandWeb.class, args);
}
}
4.配置Security的介面卡
package com.hand.config;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
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.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hand.service.UserService;
/**
* 介面卡
* Security的認證策略
* @author DoubleC
*
*/
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
UserService userService;
@Autowired
CustomExpiredSessionStrategy customExpiredSessionStrategy;
/*
* @Autowired JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
*/
/**
* 密碼進行加密
* @return
*/
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
//return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
//super.configure(auth);
// auth.inMemoryAuthentication()
// .withUser("root").password("909396").roles("ADMIN","DBA")
// .and()
// .withUser("admin").password("909396").roles("ADMIN","USER")
// .and()
// .withUser("sang").password("909396").roles("USER");
/**
* 將使用者與資料庫進行對接,並將密碼加密匹配
*/
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
//super.configure(http);
http
.authorizeRequests()
/**
* 資源管理許可權配置
*/
.antMatchers("/static/**").permitAll()
.antMatchers("/images/**").permitAll()
.antMatchers("/WEB/**").permitAll()
.antMatchers("/dynamic/**").access("hasAnyRole('admin','dba','user')")
//.access("hasRole('ADMIN') and hasRole('DBA') and hasRole('USER')")
//.antMatchers("/user/**").permitAll()
.antMatchers("/admin/**")
.hasRole("admin")
.antMatchers("/user/**")
.access("hasAnyRole('admin','dba','user')")
//.access("hasRole('admin') and hasRole('user')")
.antMatchers("/db/**")
.access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest()
.authenticated()
.and()
/**
* 登入表單詳細配置
*/
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/user/login")
/*
* .usernameParameter("username") .passwordParameter("password")
*/
.permitAll()
/**
* 登入成功實現資料互動
*/
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication auth) throws IOException, ServletException {
// TODO Auto-generated method stub
/**
* 前後端資料互動配置
*/
Object principal = auth.getPrincipal();
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
response.setStatus(200);
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", principal);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
/**
* 登入失敗進行資料互動
*/
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
// TODO Auto-generated method stub
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
response.setStatus(401);
Map<Object, Object> map = new HashMap<>();
map.put("status", 401);
if(e instanceof LockedException) {
map.put("msg", "賬戶被鎖定,登入失敗!");
}else if(e instanceof BadCredentialsException) {
map.put("msg", "賬戶或密碼輸入錯誤,登入失敗!");
}else if(e instanceof DisabledException) {
map.put("msg", "賬戶被禁用,登入失敗");
}else if(e instanceof AccountExpiredException) {
map.put("msg", "賬戶已過期,登入失敗");
}else if(e instanceof CredentialsExpiredException) {
map.put("msg", "密碼已過期,登入失敗");
}else {
map.put("msg", "登入失敗");
}
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
/**
* 登出登入配置
*/
.and()
.logout()
.logoutUrl("/logout")
.clearAuthentication(true)
.invalidateHttpSession(true)
.addLogoutHandler(new LogoutHandler() {
@Override
public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication auth) {
// TODO Auto-generated method stub
}
})
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication auth) throws IOException, ServletException {
// TODO Auto-generated method stub
//登出以後返回介面
response.sendRedirect("/login_page");
}
})
.permitAll()
/**
* 解決jsp頁面iframe全部失效問題
* X-Frame-Options' to 'deny'故障
* iframe全部失效了
* index:
* 1 Refused to display
* 'http://localhost:8080/dynamic/page/ecg.jsp'
* in a frame because it set 'X-Frame-Options' to 'deny'.
*/
.and()
.headers().frameOptions().disable()
.and()
/**
* 解決賬號同時線上問題,在同一時間只允許一個一臺機器線上
*/
.sessionManagement().maximumSessions(1).expiredSessionStrategy(customExpiredSessionStrategy).expiredUrl("/login");
http
.csrf()
.disable();
http.headers().cacheControl();
//http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
http.logout().logoutSuccessUrl("/login");
http.rememberMe().rememberMeParameter("remember");
}
}
4.1(UserService)
UserService.java
package com.hand.service;
import javax.servlet.http.HttpSession;
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;
import com.hand.mapper.UserMapper;
import com.hand.pojo.User;
@Service
public class UserService implements UserDetailsService{
@Autowired
UserMapper userMapper;
@Autowired
HttpSession session;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
//根據使用者名稱獲取使用者的基本資訊
User user=userMapper.loadUserByUsername(username);
session.setAttribute("user", user);
// UsernamePasswordToken token = new UsernamePasswordToken();
// Subject subject = SecurityUtils.getSubject();
// try {
// subject.login(token);
// } catch (Exception e) {
// // TODO: handle exception
// }
if(user==null||user.equals(" ")) {
System.out.println("賬號或密碼錯誤!");
throw new UsernameNotFoundException("賬戶不存在!");
}
//獲取使用者的許可權,並將使用者許可權表嵌入user中
user.setRoles(userMapper.getUserRolesByUid(user.getId()));
return user;
}
}
4.2(CustomExpiredSessionStrategy)
CustomExpiredSessionStrategy.java(不是必須類,可要可不要)
package com.hand.config;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
@Component
public class CustomExpiredSessionStrategy implements SessionInformationExpiredStrategy {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
Map<String,Object> map = new HashMap<>();
map.put("code",0);
map.put("msg","已經另一臺機器登入,您被迫下線。" + event.getSessionInformation().getLastRequest());
String s = objectMapper.writeValueAsString(map);
event.getResponse().setContentType("application/json;charset=UTF-8");
event.getResponse().getWriter().write(s);
event.getResponse().sendRedirect("/login");
}
}
4.3(RegService)
RegService.java (使用者註冊,給密碼進行加密,存入資料庫)
package com.hand.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.hand.mapper.UserMapper;
import com.hand.pojo.User;
@Service
public class RegService {
@Autowired
UserMapper userMapper;
public Boolean reg(String username,String password) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
String encodePassword=encoder.encode(password);
return saveToOb(username,encodePassword);
}
private Boolean saveToOb(String username, String encodePassword) {
User user = new User();
user.setUsername(username);
user.setPassword(encodePassword);
/**
* 註冊新使用者
* 根據使用者名稱查詢使用者ID
* 根據使用者ID給使用者賦予許可權最低許可權(使用者許可權)
*/
Integer userId=userMapper.userInsert(username,encodePassword);
Integer uid=userMapper.getUserId(username);
Integer user_roldId=userMapper.insertUserRole(uid);
if(userId>=1) {
if(user_roldId>=1)
return true;
return false;
}
return false;
}
}
4.4(UserMapper )
package com.hand.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.hand.common.MyMapper;
import com.hand.pojo.Role;
import com.hand.pojo.User;
public interface UserMapper extends MyMapper<User>{
User loadUserByUsername(String username);
List<Role> getUserRolesByUid(String id);
int userInsert(@Param("username")String username, @Param("password")String encodePassword);
Integer getUserId(String username);
Integer insertUserRole(Integer id);
}
4.5 (Role )
package com.hand.pojo;
public class Role {
private Integer id;
private String name;
private String namezh;
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;
}
public String getNamezh() {
return namezh;
}
public void setNamezh(String namezh) {
this.namezh = namezh;
}
@Override
public String toString() {
return "Role [id=" + id + ", name=" + name + ", namezh=" + namezh + "]";
}
}
4.6(User )
package com.hand.pojo;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.Id;
import javax.persistence.Transient;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
public class User implements UserDetails,Serializable{
@Id
private String id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
@Transient
private List<Role> roles;
/*
* public User(Integer id, String username, String password, Boolean enabled,
* Boolean locked) { // TODO Auto-generated constructor stub
* this.username=username; this.password=password; this.enabled=enabled;
* this.locked=locked; }
*/
public String getId() {
return id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public void setId(String id) {
this.id = id;
}
/*
* public Boolean getEnabled() { return enabled; }
*
* public void setEnabled(Boolean enabled) { this.enabled = enabled; }
*/
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", enabled=" + enabled
+ ", locked=" + locked + ", roles=" + roles + "]";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for(Role role:roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return !locked;
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
/*
* if (StringUtils.isEmpty(getEnabled()) ) { return !enabled; }
*/
return enabled;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return username.hashCode();
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return this.toString().equals(obj.toString());
}
}
5.書寫SQL語句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hand.mapper.UserMapper">
<select id="loadUserByUsername" resultType="com.hand.pojo.User">
select * from user where username=#{username}
</select>
<select id="getUserRolesByUid" resultType="com.hand.pojo.Role">
select * from role r,user_role ur where r.id=ur.rid and ur.uid=#{id}
</select>
<insert id="userInsert">
insert into user(id,username,password,enabled,locked) values(null,#{username},#{password},1,0);
</insert>
<select id="getUserId" resultType="java.lang.Integer">
select id from user where username=#{username}
</select>
<!-- 給使用者賦予最低等許可權3(普通使用者許可權) -->
<insert id="insertUserRole">
insert into user_role(id,uid,rid) values(null,#{id},3)
</insert>
</mapper>
6.資料表構造
CREATE TABLE USER(
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY UNIQUE,
username VARCHAR(32) NOT NULL UNIQUE ,
PASSWORD VARCHAR(255),
enabled TINYINT(1) NOT NULL,
locked TINYINT(1) NOT NULL
) ENGINE =INNODB DEFAULT CHARSET=utf8;
CREATE TABLE role(
id INT(11) NOT NULL AUTO_INCREMENT,
NAME VARCHAR(32) NOT NULL,
namezh VARCHAR(32) NOT NULL ,
PRIMARY KEY (id)
) ENGINE =INNODB DEFAULT CHARSET=utf8;
-- 許可權角色關係表--
CREATE TABLE user_role(
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY UNIQUE,
uid INT(11) NOT NULL ,
rid INT(11) NOT NULL,
KEY idx_uid(uid),
KEY idx_rid(rid)
) ENGINE = INNODB DEFAULT CHARSET = utf8;
7.表資料展示