SpringBoot 集成Spring security

Spring security作为一种安全框架,使用简单,能够很轻松的集成到springboot项目中,下面讲一下如何在SpringBoot中集成Spring Security.使用gradle项目管理工具。

 准备数据,

CREATE TABLE `user` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `roles` varchar(200) DEFAULT 'USER',
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

insert into `user` values(0,'admin','admin','SUPER,role');  //给不同个用户配置不同的权限
insert into `user` values(1,'role','role','role');

 

1:配置buildgradle,添加spring boot插件和spring security

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath('org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE')
    }
}
group "com.li"
version "1.0-SNAPSHOT"
apply plugin: "java"                           //java 插件
apply plugin: "org.springframework.boot"   //spring boot 插件
apply plugin: "io.spring.dependency-management"

apply plugin: "application"   //应用
mainClassName = "com.li.SpringBootShrioApplication"
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web",
            "org.springframework.boot:spring-boot-starter-activemq",
            "org.springframework.boot:spring-boot-starter-test",
            "org.springframework.boot:spring-boot-starter-cache",
            "org.springframework.boot:spring-boot-devtools",
            "mysql:mysql-connector-java:5.1.35",
            'org.apache.commons:commons-lang3:3.4',
            'org.apache.commons:commons-pool2',
            "org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.0",
            'org.apache.logging.log4j:log4j-core:2.7',
            'org.springframework.boot:spring-boot-starter-security',
            'org.springframework.boot:spring-boot-starter-thymeleaf',
            'org.thymeleaf.extras:thymeleaf-extras-springsecurity4',  //thymeleaf模板,集成 springsecurity4
'net.sourceforge.nekohtml:nekohtml' ) testCompile group: 'junit', name: 'junit', version: '4.12' }

2:配置spring boot, application.yml

    

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/springsecurity
    username: root
    password: 1367356
  thymeleaf:
    mode: LEGACYHTML5
    cache: false

  devtools:
    restart:
      enabled: true
server:
  port: 8081
mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml   #Mapper所在的配置文件路径,进行扫描
  config-location: classpath:mybatis/mybatis-config.xml  # mybaits-config文件

3:配置Spring Security 

WebSecurityConfig.java 继承 WebSecurityConfigurerAdapter.
当访问项目时,安全管理器按照配置进行拦截,验证通过才能访问Controller相应的路径。
package com.li.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    MyUserDetailsService myUserDetailsService;

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(myUserDetailsService);
        authenticationProvider.setPasswordEncoder(this.bCryptPasswordEncoder());
        return authenticationProvider;
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService).passwordEncoder(this.bCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        String[] s=null;
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/user/settings").authenticated() // order matters
                .antMatchers("/", "/js/**", "/css/**","/avatar/**", "/images/**", "/fonts/**", "/bootstrap-select/**", "/bootstrap-datetimepicker/**", "/custom/**", "/daterangepicker/**", "/chartjs/**").permitAll() // these paths are configure not to require any authentication
                .antMatchers("/post/**").permitAll() // all posts are allowed to be viewed without authentication
//                .antMatchers("/user/**").permitAll() // all user profiles are allowed to be viewed without authentication
                .antMatchers("/category/**").permitAll() // all categories are allowed to be viewed without authentication
                .antMatchers("/user/registration").permitAll()
                .antMatchers("/avatar/**").permitAll() // temp
                .antMatchers("/visitor/**").permitAll() // temp
//                .antMatchers("/admin/**").hasAnyRole("SUPER","USER")
//                .antMatchers("/admin/**").
//                .antMatchers("/admin/**").hasAnyRole(s)
            .anyRequest().authenticated() // every request requires the user to be authenticated
                    .and()
            .formLogin()
                .loginPage("/user/login")
                .permitAll() // login URL can be accessed by anyone
                .and()
            .logout()
                .invalidateHttpSession(true)
                .clearAuthentication(true)
                .logoutSuccessUrl("/?logout")
                .permitAll();
    }
}

  验证:对访问用户进行验证

package com.li.security;

import com.li.dao.User;
import com.li.service.UserService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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 java.util.ArrayList;
import java.util.List;

@Service
public class MyUserDetailsService implements UserDetailsService{

    Logger logger = LogManager.getLogger(MyUserDetailsService.class);
    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = this.userService.findUserByUserName(username);
        logger.debug(user.getUserName()+"密码"+user.getPassword());
        if(null == user) {
            throw new UsernameNotFoundException("Can't find user by username: " + username);
        }

        List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<>();
        // grant roles to user
        for (String role : user.getRolesSet()) {
            logger.debug(role);
            grantedAuthorities.add(new SimpleGrantedAuthority(role));  //认证
        }
//        user.setGrantedAuthorities(authorities); //用于登录时 @AuthenticationPrincipal 标签取值
        return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), grantedAuthorities);  //角色认证
    }
}

4: Controller ,Service,Dao层编写

      验证通过,Controller对相应的http处理。可以在每个http上面指定相应的访问权限

package com.li.controller;

import com.li.dao.User;
import com.li.service.UserService;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.config.ResourceNotFoundException;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.validation.Valid;
import java.util.Map;

@Controller
public class UserController {

    @Autowired
    UserService userService;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String login() {
        System.out.println("home");
        return "forum/home";
    }

    @RequestMapping(value = "/user/login", method = RequestMethod.GET)
    public String displayLoginPage(Model model) {
        System.out.println("进入");
        model.addAttribute("title", "用户登陆");
        return "forum/user-login"; //登录界面,验证没通过。
    }

    /**
     * 用户注册
     * @param model
     * @return
     */
    @RequestMapping(value = "/user/registration", method = RequestMethod.GET)
    public String showRegistrationPage(Model model) {
        System.out.println("registrationGet");
        model.addAttribute("userDto", new User());
        return "forum/user-registration";  //注册页面
    }

    @RequestMapping(value = "/user/registration", method = RequestMethod.POST)  //提交注册
    public String registerNewUser(@ModelAttribute("userDto") User user,BindingResult bindingResult,
                                  Model model, HttpServletRequest request) {
        System.out.println("registrationPost");
        Map<String, Object> attributes = this.userService.registerUserAccount(user);
        model.addAllAttributes(attributes);
        return "forum/user-registration-result";
    }


    @PreAuthorize("hasAuthority('SUPER')")  //需要SUPER用户才能通过该路径,第一步通过配置验证,没有用户登录,将会拦截,让用户登录,登录成功,访问该路径时进行角色验证。
    @RequestMapping(value = "/admin/admin", method = RequestMethod.GET)
    public String deletePost() {
        return "admin/admin";
    }

}

 Service

package com.li.service;


import com.li.dao.User;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

public interface UserService {
    public User findUserByUserName(String userName);
    public Map<String, Object> registerUserAccount(User user);
}

SeriviceImpl,对用户密码加密存储,

package com.li.service.impl;

import com.li.dao.User;
import com.li.dao.mapper.UserMapper;
import com.li.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    UserMapper userMapper;

    @Override
    public User findUserByUserName(String userName) {
        return userMapper.findByUserName(userName);
    }

    @Override
    public Map<String, Object> registerUserAccount(User userDto) {
        Map<String, Object> attributes = new HashMap<>();

        // save newly registered user
        User user = new User();

        user.setPassword(bCryptPasswordEncoder.encode(userDto.getPassword()));  //保存时应该将密码编码
        user.setUserName(userDto.getUserName());
//        user.activated(true);
        user.setRoles("USER");
//        user.setConfirmationToken(UUID.randomUUID().toString());

        // save new user and get number of affected row
//        logger.debug("用户注册");
        int affectedRow = userMapper.save(user);// populate attributes
        String registrationResult = affectedRow == 1 ? "success" : "failure";
        attributes.put("userRegistrationResult", registrationResult);
        return attributes;
    }
}

DaoMapper

package com.li.dao.mapper;

import com.li.dao.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface UserMapper {
    public User findByUserName(String username);

    public int save(@Param("user") User user);
}

普通User类

package com.li.dao;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * 实验室网站用户
 */
public class User {
    public int id;
    public String userName;
    public String password;
    public String roles;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRoles() {
        return roles;
    }

    public void setRoles(String roles) {
        this.roles = roles;
    }

    public Set<String> getRolesSet() {   //获取用户权限
        if (null == roles) {
            return null;
        }
        return Collections.unmodifiableSet(
                new HashSet<String>(Arrays.asList(getRoles().split(","))));
    }

    public void addRole(String role) {
        String currRoles = this.getRoles();
        if (null == currRoles || this.getRoles().contains(role)) {
            return;
        }
        this.setRoles(currRoles + "," + role);
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", roles='" + roles + '\'' +
                '}';
    }
}

5:编写项目的前台页面,static文件夹下面,不同权限的页面放到不同种类下面

 

posted @ 2018-05-13 16:04  1367356  阅读(921)  评论(0编辑  收藏  举报