spring boot + mybatis + spring security(自定义登录界面)环境搭建

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Aqu415/article/details/78700687

例子可以在 码云上下载:https://gitee.com/aqu415/twboot.git

概述

在前不久用了spring boot、mybatis、spring security搭建了一个工程,中间经历了各种坑,最后得到一条经验:spring的文档很详细,入门最好以官方文档为准。

这里讲的是以mav作为依赖管理工具

pom

搭建spring boot应用快捷的方式是在pom.xml中引入spring-boot-starter-parent 作为parent,如下:
<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.tw</groupId>
	<artifactId>twboot</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>twboot Maven Webapp</name>
	<url>http://maven.apache.org</url>

	<properties>
		<mybatis-spring-boot>1.2.0</mybatis-spring-boot>
	</properties>

	<!-- Spring Boot 启动父依赖 -->
	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

	<dependencies>
		<!-- 模板引擎jar包, 已经包括了spring-boot-starter-web -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!-- Spring Boot Test 依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- security -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		
		<!-- 用于thymeleaf中使用security的标签 -->
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity4</artifactId>
		</dependency>

		<!-- Spring Boot Mybatis 依赖 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>${mybatis-spring-boot}</version>
		</dependency>

		<!-- Junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>

		<!-- 上传组件包 -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>

		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.4</version>
		</dependency>
		
		<dependency>
				<groupId>javax.servlet</groupId>
				<artifactId>servlet-api</artifactId>
				<version>2.5</version>
		</dependency>

	</dependencies>

	<build>
		<finalName>twboot</finalName>
	</build>
</project>

application.yml

spring boot 中默认会获取classpath下的application.yml或者application.propertis文件作为配置文件
我用的前者
server:
  port: 80
spring:
  datasource:
    username: xyz
    password: xyz
    driver-class-name: oracle.jdbc.driver.OracleDriver
    url: jdbc:oracle:thin:@127.0.0.1:1521:XE
    dbcp2:
      max-idle: 10
      validation-query: select 1 from dual
  
  thymeleaf:
    cache: false
    prefix: classpath:/templates/
    suffix: .html
    
mybatis:
  type-aliases-package: com.tw.entity
  mapper-locations:
    - classpath:mapping/*.xml
        

上面的server.port 表示spring boot内置tomcat启动的端口是80,view层显示用的thymeleaf模板,模板前后缀也在配置文件中定义,这个和spring mvc那种配置类似;

另工程中只用用一种view表示方式,用了thymeleaf就不要用jsp了,网上说的两种模板解析链是有先后处理顺序的,也就是说是有优先级;

Springboot启动类

在我们的package最顶层新建一个继承SpringBootServletInitializer的类(内容如下),这样一个spring boot项目就搭建好了

package com.tw;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

@SpringBootApplication
@MapperScan("com.tw.dao")
public class StartApp extends SpringBootServletInitializer {
	public static void main(String[] args) {
		SpringApplication.run(StartApp.class);
	}

	//添加Tomcat支持
	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(StartApp.class);
	}
}

上面的
@SpringBootApplication 表面这是一个springboot应用,
@MapperScan("com.tw.dao")  这个表示 mybatis自动扫描dao接口的包名
这个包下的接口会自动和spring boot配置项mapper-locations中的mybatis sql配置文件映射

Controller

在spring boot中controller分为两类,一种是返回数据的Controller,一种是返回视图的Controller,分别注解是

@RestController
@Controller
我这里写一个简单的controller
package com.tw.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

import javax.servlet.ServletResponse;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class CommonController {

	@PreAuthorize("hasRole('RRR')")
	@RequestMapping(value={"/","/home"})
    public String index() {
        return "home/home";
    }
	
	@RequestMapping("/login")
	public String login(Model model) {
		System.out.println("to login----");
		return "login/login";
	}
	
	@RequestMapping("/thymeleaf")
	public String test(Map<String,Object> map,ServletResponse response) throws UnsupportedEncodingException, IOException{
		map.put("name", "test");
		System.out.println("thymeleaf----");
		return "thymeleaf/hello2";
	}
	
	/**
	 * 功能描述:角色管理
	 * CHENY037 2017年11月29日
	 * @return
	 */
	@RequestMapping("/roleManage")
	@PreAuthorize("hasRole('ROLE_MANAGE')")
	public String roleManage(){
		return "home/role";
	}
	
}

spring security

自定义登录界面和自定义用户名密码校验
配置类:
package com.tw.config.Security;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.password.PasswordEncoder;


/**
 * 配置类:
 * 配置security的登录页面和传递的参数,公共路径权限属性等
 * 
 * @author CHENY037
 *
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UrlUserService urlUserService;
    
    @Autowired
    SessionRegistry sessionRegistry;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/login").permitAll()
//                .antMatchers("/logout").permitAll()
                .antMatchers("/img/**").permitAll()
                .antMatchers("/js/**").permitAll()
                .antMatchers("/css/**").permitAll()
                .antMatchers("/bootstrap/**").permitAll()
                .antMatchers("/fonts/**").permitAll()
                .antMatchers("/favicon.ico").permitAll()
                .anyRequest().authenticated()
                //登录相关
                .and().formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password").defaultSuccessUrl("/home")
                .and().sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry)
                .and().and()
                .logout()
                .invalidateHttpSession(true)
                .clearAuthentication(true)
                .and()
                .httpBasic();
    }
    
    
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    	//这里是新增一个默认用户
        auth.inMemoryAuthentication().withUser("huahua").password("hello").roles("ADMIN");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(urlUserService).passwordEncoder(new PasswordEncoder() {

            @Override
            public String encode(CharSequence rawPassword) {
                return (String)rawPassword;//MD5Util.encode((String) rawPassword);
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
            	System.out.println(encodedPassword + "---" + (String)rawPassword);
                return encodedPassword.equals((String) rawPassword);
            }
        });
    }

    @Bean
    public SessionRegistry getSessionRegistry(){
        SessionRegistry sessionRegistry = new SessionRegistryImpl();
        return sessionRegistry;
    }
}
自定义用户名密码校验类
package com.tw.config.Security;


import java.util.ArrayList;
import java.util.List;

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.tw.dao.RoleDao;
import com.tw.dao.UserDao;
import com.tw.entity.role.TwRole;
import com.tw.entity.role.TwUser;

/**
 * 自定义用户名密码校验实现
 * 
 * @author CHANY037 2017-11
 *
 */
@Service
public class UrlUserService implements UserDetailsService {
	
    @Autowired
    UserDao userDao;
    
    @Autowired
    RoleDao roleDao;
    
    /**
     * employeeId 用户工号,在数据库中保证存储唯一
     */
    @Override
    public UserDetails loadUserByUsername(String employeeId) { //重写loadUserByUsername 方法获得 userdetails 类型用户

        TwUser user = userDao.findByEmployeeId(employeeId);
        
        if(user == null){
        	throw new UsernameNotFoundException(employeeId + " do not exist!");
        } else {
        	System.out.println(user.getPassword() + " --pw-- ");
            List<TwRole> roles = roleDao.findRoleByEmployeeId(employeeId);
            List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
            
            //写入用户的角色  ***  切记 由于框架原因 角色名称要以 ROLE_ 开头 **** 血泪史 ****
            //源码:org.springframework.security.access.expression.SecurityExpressionRoot hasAnyRole()
            for (TwRole role : roles) {
                if (role != null && role.getRoleName() != null) {
                	SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleCode());
                    grantedAuthorities.add(grantedAuthority);
                }
            }
            org.springframework.security.core.userdetails.User uu = new User(employeeId, user.getPassword(), grantedAuthorities);
            return uu;
        }
    }
}

登录界面html 即 上面
CommonController 里定义的login方法返回的视图
<!doctype html>
<html lang="en" class="no-js" 
         xmlns="http://www.w3.org/1999/xhtml" 
         xmlns:th="http://www.thymeleaf.org"
         xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8"/>

<title>Login</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<!--  thymeleaf 默认从resources 下的 static目录获取 -->
<link rel="stylesheet" th:href="@{bootstrap/css/bootstrap.min.css}"/>
<script th:src="@{js/jquery.min.js}"></script>
<script th:src="@{bootstrap/js/bootstrap.min.js}"></script>
<style>
.form-control{
width: 200px;
}
</style>
</head>

<body style="background: url(img/login.jpg);width: 98%;">

<div style="margin-top: 150px;margin-left: 800px;margin-bottom: 160px;" >

    <form class="form-horizontal" method="post" th:action="@{/login}">
			<div class="form-group">
				<label for="inputEmail3" class="col-sm-2 control-label">用户名</label>
				<div class="col-sm-10"><input autocomplete="off" type="text" class="form-control" name="username" /></div>
			</div>
			<div class="form-group">
				<label for="inputPassword3" class="col-sm-2 control-label">密码</label>
				<div class="col-sm-10">
				<input type="text" class="form-control" name="password" onfocus="this.type='password'"/>
				</div>
			</div>
			<div class="form-group">
				<div class="col-sm-offset-2 col-sm-10">
					<div class="checkbox">
						 <label><input type="checkbox" />Remember me</label><!-- 功能暂未实现 -->
					</div>
				</div>
			</div>
			<div class="form-group">
				<div class="col-sm-offset-2 col-sm-10">
					 <button type="submit" class="btn btn-default">登录</button>
				</div>
			</div>
	</form>
</div>

<!-- 引入 页脚 -->
<div th:replace="common/footer :: footer"></div>

</body>
</html>


猜你喜欢

转载自blog.csdn.net/Aqu415/article/details/78700687