zoukankan      html  css  js  c++  java
  • SpringSecurity学习之基于数据库的用户认证

      SpringSecurity给我们提供了一套最基本的认证方式,可是这种方式远远不能满足大多数系统的需求。不过好在SpringSecurity给我们预留了许多可扩展的接口给我们,我们可以基于这些接口实现自己的认证方式。

    一、前期准备工作

    1.1、创建示例数据库

    Student表:

    create table student
    (
        id int auto_increment
            primary key,
        stuName varchar(8) null,
        password varchar(16) null,
        joinTime datetime null,
        clz_id int null
    )
    ;

    Classes(班级)表:

    create table classes
    (
        id int auto_increment
            primary key,
        clz_name varchar(16) not null
    )
    ;

    1.2、添加相关依赖

    compile group: 'mysql', name: 'mysql-connector-java'
    compile group: 'org.springframework.security', name: 'spring-security-taglibs'
    compile('org.springframework.boot:spring-boot-starter-jdbc')

    二、实现步骤

    2.1  定义Student类

    package com.bdqn.lyrk.security.study.app.pojo;
    
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    
    import java.sql.Timestamp;
    import java.util.Collection;
    
    public class Student extends User {
    
        private Timestamp joinTime;
    
        public Timestamp getJoinTime() {
            return joinTime;
        }
    
        public void setJoinTime(Timestamp joinTime) {
            this.joinTime = joinTime;
        }
    
        public Student(String username, String password, Collection<? extends GrantedAuthority> authorities) {
            super(username, password, authorities);
        }
    
    }
    View Code

      在这里定义的类继承User,User是SpringSecurity里的一个类,用以描述一个用户和其最基本的属性,当然我们要扩展它的用户我们也可以实现UserDetails接口

    2.2 实现UserDetailsService

    package com.bdqn.lyrk.security.study.app.service;
    
    import com.bdqn.lyrk.security.study.app.pojo.Student;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    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 java.sql.Timestamp;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    @Service
    public class UserService implements UserDetailsService {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            User.UserBuilder users = User.withDefaultPasswordEncoder();
            Map<String, Object> map = jdbcTemplate.queryForMap("select t.clz_name,t1.stuName,t1.password,t1.joinTime from student t1 inner  join classes t on t.id = t1.clz_id where stuName = ?", username);
            Timestamp joinTime = null;
            if (map != null && map.size() > 0) {
                String stuName = (String) map.get("stuName");
                String password = (String) map.get("password");
                joinTime = (Timestamp) map.get("joinTime");
                String clzName = (String) map.get("clz_name");
                users.password(password);
                users.username(stuName);
                SimpleGrantedAuthority authority = new SimpleGrantedAuthority(clzName);
                List<GrantedAuthority> list = new ArrayList<>();
                list.add(authority);
                users.authorities(list);
            }
            UserDetails userDetails = users.build();
            Student student = new Student(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
    //        UserDetails userDetails = User.withDefaultPasswordEncoder().
            student.setJoinTime(joinTime);
            return student;
        }
    }
    View Code

      在这个接口里我们要实现根据用户名查找用户的方法,那么一般情况下我们都会根据自己系统的用户表来获取用户信息,这里面注意几个方面:

      1)需要设置PasswordEncoder 

      2) 需要设置其角色信息,那么在这里我用班级来表示用户的角色

      3)用户的三个重要属性就是 用户名,密码与权限

      4) 这里的返回值(UserDetails)不能返回null,如果根据用户名找不到对应的用户可以抛出UsernameNotFoundException异常

    2.3 改造WebSecurityConfig

    package com.bdqn.lyrk.security.study.app.config;
    
    import com.bdqn.lyrk.security.study.app.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    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;
    
    /**
     * spring-security的相关配置
     *
     * @author chen.nie
     * @date 2018/6/7
     **/
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private UserService userService;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            /*
                1.配置静态资源不进行授权验证
                2.登录地址及跳转过后的成功页不需要验证
                3.其余均进行授权验证
             */
            http.
                    authorizeRequests().antMatchers("/static/**").permitAll().
                    and().authorizeRequests().antMatchers("/user/**").hasRole("7022").
                    and().authorizeRequests().anyRequest().authenticated().
                    and().formLogin().loginPage("/login").successForwardUrl("/toIndex").permitAll()
                    .and().logout().logoutUrl("/logout").invalidateHttpSession(true).deleteCookies().permitAll()
            ;
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //设置自定义userService
            auth.userDetailsService(userService);
        }
    }
    View Code

    在这里主要做以下处理:

     1)针对于/user/**路径的请求需要设置对应的权限

     2) 做用户注销的处理,用户注销时需要销毁session与cookie

     3)配置自定义UserDetailService

    2.4、改造index.jsp

    <%--
      Created by IntelliJ IDEA.
      User: chen.nie
      Date: 2018/6/8
      Time: 上午9:56
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    欢迎:${user.username}
    <sec:authorize access="hasRole('7022')">
        加入时间:${user.joinTime}
    </sec:authorize>
    <form action="/logout" method="post">
        <input type="submit" value="退出" />
        <sec:csrfInput/>
    </form>
    
    </body>
    </html>

      在这里面我们使用spring对security标签的支持判断当前用户是否有对应的角色,另外我们在处理登出操作时必须为post提交且有对应的token防止csrf

  • 相关阅读:
    拉格朗日乘子基本概念
    "模式识别与机器学习"读书笔记——2.3(2)
    [raw]人工智能方向调查
    Android !No Launcher activity found!错误
    [raw]ubuntu在当前目录右键打开终端
    Android, 读取大型文件报错
    Blueman Ubuntu的蓝牙管理器
    VMware下Ubuntu8.04 方向键失效的解决方法
    无线中间人攻击初探
    【经验】短接 Flash 解决二次量产金士顿 DTI G2 4GB U盘(群联PS225139)问题
  • 原文地址:https://www.cnblogs.com/niechen/p/9163590.html
Copyright © 2011-2022 走看看