1. 程式人生 > >SpringBoot 集成Spring security

SpringBoot 集成Spring security

oba java tails detail logout reat password rim res

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:編寫項目的前臺頁面,不同權限的頁面放到不同種類下面

SpringBoot 集成Spring security