[SpringSecurity]搭个简易登录认证的架子/mybaits建表/userDetailService/BCryptPasswordEncoder/formLogin

目录

 

前置知识(可略):

关于表(可略)

Bean

实现UserDetailsService 

配置SecurityConfig

test

踩坑


前置知识(可略):

springboot(搭个架子,连接好jdbc,跑得通maping)

数据库关系映射(mybaitis+mysql+表结构)

security引入(pom文件)

项目目录结构

[SpringSecurity]搭个简易登录认证的架子/mybaits建表/userDetailService/BCryptPasswordEncoder/formLogin_第1张图片

关于表(可略)

ps:密码保存数据库先加密

加密示范

 BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
       String encode = bCryptPasswordEncoder.encode("123");
        System.out.println(encode);

建表 

CREATE TABLE `learn_security_per_role` (
  `role_id` int(11) DEFAULT NULL,
  `perm_id` int(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `learn_security_permission` (
  `permid` int(11) NOT NULL,
  `permTag` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `permName` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`permid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `learn_security_role` (
  `roleid` int(11) DEFAULT NULL,
  `rolename` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `roledesc` varchar(255) COLLATE utf8_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `learn_security_user` (
  `userid` int(255) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `userrealname` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `password` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `createdate` datetime DEFAULT NULL,
  `lastlogintime` datetime DEFAULT NULL,
  `isavailable` int(255) DEFAULT NULL,
  `isexpired` int(255) DEFAULT NULL,
  `islock` int(255) DEFAULT NULL,
  `identifyIsExpired` int(255) DEFAULT NULL,
  PRIMARY KEY (`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `learn_security_user_role` (
  `user_id` int(11) DEFAULT NULL,
  `role_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

 

Bean

(根据表把bean都写好,只给出user,user很重要,其他自建)

解释:此类会直接绑定security自带的login页面,也就是通过表单提交用户名密码,重写UserDetails 的几个方法,是为了给security自带的各个功能比如isLock一类,会自动关联数据库(如果你重写的话,重写记得要修改代码)

GrantedAuthority会绑定hasAnyAuthority,也要写

package com.yiki.blog.SecurityLearn;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

public class User implements UserDetails {

    private Integer userID;
    private String userName;
    private String userRealName;
    private String passWord;
    private Date creatDate;
    private Date lastLoginTime;
    private boolean isAvailable;//是否可用
    private boolean isExpired;//是否过期
    private boolean isLock;//是否锁定
    private boolean identifyIsExpired;//证书是否过期

    private List authorityList = new ArrayList();

    public void setAuthorities(List authorityList) {
        this.authorityList = authorityList;
    }

    @Override
    public Collection getAuthorities() {
        return authorityList;
    }

    @Override
    public String getPassword() {
        return passWord;
    }

    @Override
    public String getUsername() {
        return userName;
    }

    @Override
    public boolean isAccountNonExpired() {
        return isExpired;
    }

    @Override
    public boolean isAccountNonLocked() {
        return isLock;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return identifyIsExpired;
    }

    @Override
    public boolean isEnabled() {
        return isAvailable;
    }

    public Integer getUserID() {
        return userID;
    }

    public void setUserID(Integer userID) {
        this.userID = userID;
    }

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

    public String getUserRealName() {
        return userRealName;
    }

    public void setUserRealName(String userRealName) {
        this.userRealName = userRealName;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public Date getCreatDate() {
        return creatDate;
    }

    public void setCreatDate(Date creatDate) {
        this.creatDate = creatDate;
    }

    public Date getLastLoginTime() {
        return lastLoginTime;
    }

    public void setLastLoginTime(Date lastLoginTime) {
        this.lastLoginTime = lastLoginTime;
    }

    public boolean isAvailable() {
        return isAvailable;
    }

    public void setAvailable(boolean available) {
        isAvailable = available;
    }

    public boolean isExpired() {
        return isExpired;
    }

    public void setExpired(boolean expired) {
        isExpired = expired;
    }

    public boolean isLock() {
        return isLock;
    }

    @Override
    public String toString() {
        return "User{" +
                "userID=" + userID +
                ", userName='" + userName + '\'' +
                ", userRealName='" + userRealName + '\'' +
                ", passWord='" + passWord + '\'' +
                ", creatDate=" + creatDate +
                ", lastLoginTime=" + lastLoginTime +
                ", isAvailable=" + isAvailable +
                ", isExpired=" + isExpired +
                ", isLock=" + isLock +
                ", identifyIsExpired=" + identifyIsExpired +
                ", authorityList=" + authorityList +
                '}';
    }

    public void setLock(boolean lock) {
        isLock = lock;
    }

    public boolean isIdentifyIsExpired() {
        return identifyIsExpired;
    }

    public void setIdentifyIsExpired(boolean identifyIsExpired) {
        this.identifyIsExpired = identifyIsExpired;
    }
}

Mapper

package com.yiki.blog.SecurityLearn;


import org.apache.ibatis.annotations.Mapper;

import java.util.List;
@Mapper
public interface UserMapper {

    public User getUserByUserName(String name);

    //查询用户拥有的权限
    public List getPermissionByUserName(String name);
}





    

    


实现UserDetailsService 

在这里写了会自动绑定login页面(自带那个)

package com.yiki.blog.SecurityLearn;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
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;

//security提供的自定义类的用户信息巴拉巴拉(可构造)
//UserDetails 接口

@Service
public class YikiUserDetailService implements UserDetailsService {


    @Autowired
    private UserMapper userMapper;

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

        User user = userMapper.getUserByUserName(username);

        List permList = userMapper.getPermissionByUserName(username);
        List grantedAuthorities = new ArrayList<>();
        for (Permission perm : permList) {
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(perm.getPermName());
            grantedAuthorities.add(grantedAuthority);
        }

        user.setAuthorities(grantedAuthorities);
        return user;
    }
}

配置SecurityConfig

权限参考

[SpringSecurity]搭个简易登录认证的架子/mybaits建表/userDetailService/BCryptPasswordEncoder/formLogin_第2张图片

package com.yiki.blog.SecurityLearn;

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.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;

//1配置类
@Configuration
@EnableWebSecurity//2启动security过滤器链

//3继承这个配置类
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //4.重写这两个方法


    //7.在登录页用封装好的userdetail
    @Autowired
    private YikiUserDetailService userDetailService;



    /**
     * 5-1代替xml配置的AuthenticationManager(认证管理器)
     * 认证的信息获取
     */
    @Override//
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        /*6.2.A
         * 写死的配置---~硬编码
         * There is no PasswordEncoder mapped for the id “null”
         * 时过境迁,psw报错id为null是因为security默认会对密码解密方式需要定义,也就是{id},若没有则为null,则会报错
         * 记得在设置密码给个加密方式 *

        auth.inMemoryAuthentication()
                .passwordEncoder(new BCryptPasswordEncoder())
                .withUser("Admin")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .authorities("Auth");//可以用,追加权限

*/
        /*
        * 6.2 B自定义service类
        * */
        auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder());;

    }

    /**
     * 5-2.代替之前标签配置
     * 需要拦截资源/角色权限/登录方式:httpBasic,FormLogin)
     * spring拦截到的http会转发到这里
     * 其他:/**全部路径,/*一级路径
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        /*6-1拦截表达式A.httpBasic
        http.authorizeRequests()
                .antMatchers("/**")
                .fullyAuthenticated()
                .and()
                .httpBasic();

                          @isAuthenticated()
                          Returns true if the user is not anonymous
                          @isFullyAuthenticated()
                           Returns true if the user is not an anonymous or a remember-me user
                          @anonymous()
                           只有匿名用户可以访问资源,登录后不允许访问
                          * */

        /*B.formLogin
         * */
        http.authorizeRequests()
                .antMatchers("/security/*").hasAnyAuthority("ROLE_SEARCH,ROLE_DELETE")
                .and().csrf().disable()//禁止自带跨域
                .formLogin();
    }
}

test

package com.yiki.blog.SecurityLearn;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

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

@ResponseBody
@Controller
@RequestMapping("/security")
public class TestController {

    @Autowired
    UserMapper userMapper;


    @GetMapping("/name1")
    public User index1() {

        User user = new User();
        user = userMapper.getUserByUserName("yiki");
        List permList = userMapper.getPermissionByUserName("yiki");
        List grantedAuthorities = new ArrayList<>();
        for (Permission perm : permList) {
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(perm.getPermTag());
            grantedAuthorities.add(grantedAuthority);
        }
        user.setAuthorities(grantedAuthorities);
        System.out.println(user);
        return user;
    }

    @GetMapping("/name2")
    public List name2() {
        return userMapper.getPermissionByUserName("yiki");
    }
}

 

踩坑

1. Empty encoded password

user类重写的方法里password不能返回null,而是

 @Override
    public String getPassword() {
        return passWord;
    }

2.There is no PasswordEncoder mapped for the id "null"

这个就是密码前{id}xxx是指告诉框架加密方式

硬编码处

 auth.inMemoryAuthentication()
                .passwordEncoder(new BCryptPasswordEncoder())
                .withUser("Admin")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .authorities("Auth");//可以用,追加权限

 

你可能感兴趣的:(Spring)