天天看點

SpringBoot整合SecuritySpringBoot整合Security

SpringBoot整合Security

目前市面上主流的權限控制架構有:shiro和Spring Security,本人更青睐Spring Security,是以下面為大家講解下springboot與這個權限架構的整合!

RBAC權限模型

首先先來介紹下什麼是RBAC?RBAC(Role-Based Access Control)從字面意思上來看,是基于角色的通路控制,簡單來說就是,一個使用者擁有多個角色,一個角色擁有多個權限,使用者與角色是多對多,角色與權限也是多對多,于是就形成了使用者-角色-權限這個模型。

securiity核心思想

核心:開啟過濾器去攔截所有請求,裡面有很多過濾器,每個過濾器都專門做一種認證和授權

security認證授權有兩種方式:

1、表單送出認證formlogin,這個架構自身提供了登入頁面,但是在開發中最好自己寫登入頁面

2、htppbasic模式,它是浏覽器和伺服器進行認證授權的

如何進行權限控制?

給每一個請求路徑 配置設定一個權限名稱 然後賬号隻要關聯該名稱,就可以有通路權限

加入Springboot內建security的相關依賴

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.1.RELEASE</version>
	</parent>
	<!-- 管理依賴 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR4</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<dependencies>
		<!-- SpringBoot整合Web元件 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<!-- springboot整合freemarker -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>
		<!-->spring-boot 整合security -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<!-- springboot 整合mybatis架構 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<!-- alibaba的druid資料庫連接配接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.9</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
	</dependencies>
           

實體設計

使用者類:一定要去實作UserDetails 這個類,裡面封裝了這個實體所需要的字段

@Data
public class User implements UserDetails {
	private Integer id;
	private String username;
	private String realname;
	private String password;
	private Date createDate;
	private Date lastLoginTime;
	// 使用者所有權限
	private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
           

角色類

@Data
public class Role {
	private Integer id;
	private String roleName;
	private String roleDesc;
}
           

權限類

@Data
public class Permission {
	private Integer id;
	private String permName;// 權限名稱
	private String permTag;// 權限辨別
	private String url;	// 請求url
}
           

持久層mapper

public interface UserMapper {
	// 查詢使用者資訊
	@Select(" select * from sys_user where username = #{userName}")
	User findByUsername(@Param("userName") String userName);

	// 查詢使用者的權限
	@Select(" select permission.* from sys_user user" + " inner join sys_user_role user_role"
			+ " on user.id = user_role.user_id inner join "
			+ "sys_role_permission role_permission on user_role.role_id = role_permission.role_id "
			+ " inner join sys_permission permission on role_permission.perm_id = permission.id where user.username = #{userName};")
	List<Permission> findPermissionByUsername(@Param("userName") String userName);
}
           

service實作類

@Component
public class UserService implements UserDetailsService {
	@Autowired
	private UserMapper userMapper;
	// 查詢使用者資訊
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// 根據使用者查詢使用者資訊
		User user = userMapper.findByUsername(username);
		// 根據使用者查詢使用者對應權限
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		List<Permission> listPermission = userMapper.findPermissionByUsername(username);
		for (Permission permission : listPermission) {
			authorities.add(new SimpleGrantedAuthority(permission.getPermTag()));
		}
		// 設定使用者權限
		user.setAuthorities(authorities);
		return user;
	}
}
           

Security 配置

動态查詢資料庫,将使用者、角色與權限進行關聯查詢,這裡是使用formlogin表單送出認證的,最後要注意表單中傳過來的密碼要進行加密之後再與資料庫中的密碼進行比對,認證通過之後則放行,否則登入失敗。

@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private PermissionMapper permissionMapper;
	@Autowired
	private UserService userService;
	// 配置認證使用者資訊和權限
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(myUserDetailService).passwordEncoder(new PasswordEncoder() {
		//将資料庫查詢出來的密碼encodedPassword和表單中傳過來的密碼rawPassword進行比對,注意這裡密碼必須加密
			public boolean matches(CharSequence rawPassword, String encodedPassword) {
				String encode = MD5Util.encode((String) rawPassword);
				encodedPassword=encodedPassword.replace("\r\n", "");
				boolean result = encodedPassword.equals(encode);
				return result;
			}
			public String encode(CharSequence rawPassword) {
				return MD5Util.encode((String) rawPassword);
			}
		});
	}
	// 配置攔截請求資源
	protected void configure(HttpSecurity http) throws Exception {
		// 動态配置查詢産品權限
		List<Permission> listPermission = permissionMapper.findAllPermission();
		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry    			   authorizeRequests = http.authorizeRequests();
		for (Permission permission : listPermission) {
	authorizeRequests.antMatchers(permission.getUrl()).hasAnyAuthority(permission.getPermTag());
		}
	authorizeRequests.antMatchers("/login").permitAll().antMatchers("/**")
	.fullyAuthenticated().and().formLogin().loginPage("/login").and().csrf().disable();
	}
           

controller類

@Controller
public class ProductController {
	// 自定義登陸頁面
	@GetMapping("/login")
	public String login() {
		return "login";
	}
	// 首頁
	@RequestMapping("/")
	public String index() {
		return "index";
	}
	// 查詢産品
	@RequestMapping("/showProduct")
	public String showProduct() {
		return "showProduct";
	}
	// 添加産品
	@RequestMapping("/addProduct")
	public String addProduct() {
		return "addProduct";
	}
	// 修改産品
	@RequestMapping("/updateProduct")
	public String updateProduct() {
		return "updateProduct";
	}
	// 删除産品
	@RequestMapping("/deleteProduct")
	public String deleteProduct() {
		return "deleteProduct";
	}
           

登入頁面

<body>
	<h1>權限登陸系統</h1>
	<form action="/login" method="post">
		<span>使用者名稱</span><input type="text" name="username" /> <br>
		<span>使用者密碼</span><input type="password" name="password" /> <br>
		<input type="submit" value="登陸"> 
	</form>
</body>
           

首頁

<h1>産品管理</h1>
<br>
<a href="showProduct">查詢産品</a>
<br>
<a href="addProduct">添加産品</a>
<br>
<a href="deleteProduct">删除産品</a>
<br>
<a href="updateProduct">修改産品</a>
           

至此,springboot與security架構的內建就結束了。建議學習過程多看文檔,多看源碼,此部落格僅供學習交流使用。