最近在跟着某佬写项目,因为不是我搭架子,然后开始前告诉我说要用到springsecurity
叫我先去看看,因为我还要准备高数的期中考试,于是就在写项目的途中边学边写,
感觉真的是要多爽就有多爽。于是就去GitHub里面找了一个项目来学security框架,
磕磕碰碰幸好还是走通了,话不多说,直接上干货。

首先看看我的项目结构图,我感觉这个是关键
在这里插入图片描述

然后是我的数据库设计和数据库里面的数据的图,这个。一般重要吧。(ps:我用的sqlyog,感觉蛮好用的,安利一波)
在这里插入图片描述
数据库也没什么内容就三种权限
在这里插入图片描述

好了,该看的图都有了,那就开始干吧
首先是建立一个springboot项目,这个就不在这里说了,然后就是配置pom.xml了,要是不放心可以直接复制粘贴我的,已试毒。

<?xml version="1.0" encoding="UTF-8"?>
<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>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>springboot_mybatis_springsecurity_merge</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot_mybatis_springsecurity_merge</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.0.1</version>
		</dependency>

		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
		
		
		<!-- Junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>



		
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-taglibs</artifactId>
		</dependency>
		
		<!-- lombok -->
		<dependency>
	      <groupId>org.projectlombok</groupId>
	      <artifactId>lombok</artifactId>    
	    </dependency>
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity4</artifactId>
			<version>3.0.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.36</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

接着是配置application.xml这里也可以直接复制我的。(ps:数据库记得该成自己的)

server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/xxx
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.mvc.view.suffix=.html

配完之后就可以开始写啦(PS:写之前或者最后去建立数据库都是可以的)
我是先写的实体类,因为实体类最好写,代码太长就不贴了(PS:最后会给GitHub的传送门,莫急)
然后就是写mapper,我这里直接用的注解,很短,可以贴上来看看

package com.example.demo.dao;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

import com.example.demo.domain.SecurityUser;
@Mapper
@Repository
public interface SecurityUserMapper {
	@Select("SELECT * FROM security_user WHERE username=#{username}")
	SecurityUser findSecurityUserByUsername(String username);
}

好了,现在没用security框架之前我们能写的全部都写完了,接下来就是写security的部分了,刺激。
首先我们要写一个UserDetailsService的实现类,因为我们需要自定义的登录,(因为security本身会给一个登录的界面,显然我们不可能用哪个)
具体代码我贴上来,因为里面有注释就不多说了,看不懂的可以评论,一起讨论一起进步

package com.example.demo.service;

import java.util.ArrayList;
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.example.demo.dao.SecurityUserMapper;
import com.example.demo.domain.SecurityUser;

/**
 * service注解是必须的,还要记得在配置类当中加载
 * @author 11366
 *
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

	@Autowired
	private SecurityUserMapper dao;

	//通过用户名得到用户信息并注册进去
	//重写这个方法自己来实现登录验证
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		SecurityUser suuser = dao.findSecurityUserByUsername(username);

		if (suuser == null) {
			System.out.println(username + "is not exist!");
			throw new UsernameNotFoundException(username + "不存在");
		}

		UserDetails user = new User(username, suuser.getPassword(), true, true, true, true,
				getAuthorities(suuser.getAccess_level()));

		return user;
	}

	// 得到用户所拥有的权限
	public Collection<GrantedAuthority> getAuthorities(int access){
		Collection<GrantedAuthority> authorities = new ArrayList<>();
		//首先所有的都拥有用户权限
		authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
		//如果是0,那就是用户加管理员
		if(access==0) {
			authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
		}
		//如果是2,那就是介于管理员和普通用户之间的权限,相当于可以理解为vip吧
		if(access == 2) {
			authorities.add(new SimpleGrantedAuthority("ROLE_TWO"));
		}
		
		return authorities;
	}
	
}

写完之后就来到了最重要的部分,配置类了,之所以留到最好就是为了大家可以慢慢的接受,我反正是这样想的,之前的代码肯定没问题,那接下俩的肯定也没有问题。货不多说,上代码。

package com.example.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
/**
 * 配置类,重写他的一些方法来设置一些web安全的细节如配置security的登录页面和传递参数,公共路径权限属性
 */
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import com.example.demo.service.PasswordEncoderImpl;
import com.example.demo.service.UserDetailsServiceImpl;
@Configuration
//请求控制权限到方法级别
@EnableGlobalMethodSecurity(securedEnabled = true)
//可以达到禁用默认登录界面
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	//自定义认证对象
	@Autowired
	private UserDetailsServiceImpl serviceImpl;

	//自定义登录规则就必须要重写这个方法
	//身份验证管理生成器
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		//不加.passwordEncoder(new PasswordEncoderImpl())
        //就不是以明文的方式进行匹配,会报错
		auth.userDetailsService(serviceImpl).passwordEncoder(new PasswordEncoderImpl());
	}

	//http请求安全处理
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		//请求权限配置
		
		http.authorizeRequests()
		.antMatchers("/","/login").permitAll()
		.anyRequest().authenticated()
		.and().formLogin().loginPage("/login").defaultSuccessUrl("/hello").permitAll()
		.and().logout().logoutSuccessUrl("/login").permitAll()
		.and().exceptionHandling().accessDeniedPage("/denied");
		//禁止使用默认的csrf
		http.csrf().disable();
	}
	
	
}

OK接下来验证的时刻了,也就是controller,在那里面我是直接用的@Secured注解,还有一种方式我没有用,因为考虑到这可能是入门,简单点更好。

package com.example.demo.controller;

import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloController {

	@RequestMapping("/hello")
	@Secured("ROLE_USER")
	public String hello() {
		return "hello";
	}
	
	@RequestMapping("/login")
	public String login() {
		return "login";
	}
	@RequestMapping("/logout")
	public String logout() {
		return "home";
	}
	
	@RequestMapping("/denied")
	public String denied() {
		return "denied";
	}
	
	@RequestMapping("/admin")
	@Secured("ROLE_ADMIN")
	public String admin() {
		return "admin";
	}
}

好了,差不错就是这样了,等等,还有一个很重要的点,因为security框架并不是采用铭文传输,所以要么你数据库用md5加密,不过这样就麻烦了(也不麻烦其实但是考虑到入门嘛)于是我就直接用明文,用明文就需要实现PasswordEncoder接口啦,上代码

package com.example.demo.service;
/**
 * 
 */
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
public class PasswordEncoderImpl implements PasswordEncoder {

	@Override
	public String encode(CharSequence rawPassword) {
		// TODO Auto-generated method stub
		return rawPassword.toString();
	}

	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		// TODO Auto-generated method stub
		return encodedPassword.equals(rawPassword.toString());
	}

}

就是在配置security哪里加入,截图吧,有图有真相
在这里插入图片描述
OK,传送门明天再写吧。,顶不住了。回寝室啦

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐