Spring Security(二)

        在 上一节 我们完成了最基本的security配置,下面我们了解下如何配置用户信息,包括内存签名服务数据库签名服务自定义签名服务三种。

首先,说下内存签名服务,顾名思义,就是将用户的相关信息放在内存中,一般用于项目初期的环境搭建验证。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //用户信息加解密,单向不可逆
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //在这里配置url访问权限
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests().anyRequest().authenticated()
                .and().formLogin();
    }


    /*
    * 该方法是一个配置用户信息的方法,
    * 使用内存签名服务,数据库签名服务和自定义签名服务
    * 通过configure(HTTPSecurity httpSecurity)方法限定请求权限
    * */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //密码编码器
        PasswordEncoder passwordEncoder = passwordEncoder();
        //内存签名服务
        auth.inMemoryAuthentication()
                .passwordEncoder(passwordEncoder)
                //注册用户admin,密码为123456,赋予用户和管理员的权限
                .withUser("admin")
                .password("$2a$10$6oba6BnY4Ux/ayNTX1KcOO6ZYYb17rnMmsL.bOg2wqU5UsfbLYfBO")
                .roles("USER", "ADMIN")
                .and()
                //注册用户user,密码为123456
                .withUser("user")
                .password("$2a$10$6oba6BnY4Ux/ayNTX1KcOO6ZYYb17rnMmsL.bOg2wqU5UsfbLYfBO")
                .roles("USER");
    }
}

 在spring 5的Security中都要求使用密码编码器,否则发生异常。inMemoryAuthentication()方法配置用户的信息,包括赋予角色。我们可以先写一个UserController页面和user页面看下效果。

UserController如下:

@Controller
public class UserController {

    @GetMapping("/user")
    public String user(){
        return "user";
    }
}

在src/resources/templates下新建一个user.heml。内存如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>welcome you, my lover!</h1>
</body>
</html>

然后,我们启动下试试效果,输入http://localhost:8080/ ,输入用户名和密码

接下来,就是通过访问数据库的信息来实现登录。

数据库主要有三个表,其中t_role表是角色表,就是说明有哪些角色(管理员,用户等);t_user表为用户表,包含用户的信息;t_user_role表为用户角色表(将角色表和用户表对应)。

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_role
-- ----------------------------
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `note` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_role
-- ----------------------------
INSERT INTO `t_role` VALUES (1, 'ROLE_ADMIN', NULL);
INSERT INTO `t_role` VALUES (2, 'ROLE_USER', NULL);

-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `id` int(12) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `pwd` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `available` int(1) NULL DEFAULT 1 COMMENT '是否可用,1表示可用,0表示不可用',
  `note` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `user_name`(`user_name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, 'admin', '$2a$10$JqRPoogLhSHKlP5esSSJ2eMBQdyjeiOYRkl73EC2tD2Swuj1NpkCG', 1, 'ROLE_ADMIN,ROLE_USER');
INSERT INTO `t_user` VALUES (2, 'myuser', '$2a$10$JqRPoogLhSHKlP5esSSJ2eMBQdyjeiOYRkl73EC2tD2Swuj1NpkCG', 1, 'ROLE_USER');

-- ----------------------------
-- Table structure for t_user_role
-- ----------------------------
DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role`  (
  `id` int(12) NOT NULL AUTO_INCREMENT,
  `role_id` int(12) NOT NULL,
  `user_id` int(12) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `role_id`(`role_id`, `user_id`) USING BTREE,
  INDEX `FK_Reference_2`(`user_id`) USING BTREE,
  CONSTRAINT `FK_Reference_1` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `FK_Reference_2` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_user_role
-- ----------------------------
INSERT INTO `t_user_role` VALUES (1, 1, 1);
INSERT INTO `t_user_role` VALUES (2, 2, 1);
INSERT INTO `t_user_role` VALUES (3, 2, 2);

SET FOREIGN_KEY_CHECKS = 1;

在这里,更改下SecurityConfig类,

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //注入数据源
    @Autowired
    private DataSource dataSource = null;
    //使用用户名查询密码
    String pwdQuery = "select user_name, pwd, available from t_user where user_name =?";
    //使用用户名查询角色信息
    String roleQuery = "select u.user_name, r.role_name from t_user u, t_user_role ur, t_role r "
            + "where u.id = ur.user_id and r.id = ur.role_id and u.user_name =?";

    //用户信息加解密,单向不可逆
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //在这里配置url访问权限
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests().anyRequest().authenticated()
                .and().formLogin();
    }


    /*
    * 该方法是一个配置用户信息的方法,
    * 使用内存签名服务,数据库签名服务和自定义签名服务
    * 通过configure(HTTPSecurity httpSecurity)方法限定请求权限
    * */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //密码编码器
        PasswordEncoder passwordEncoder = passwordEncoder();
        auth.jdbcAuthentication()
                .passwordEncoder(passwordEncoder)
                //数据源
                .dataSource(dataSource)
                //查询用户,自动判断密码是否一致
                .usersByUsernameQuery(pwdQuery)
                //赋予权限
                .authoritiesByUsernameQuery(roleQuery);
    }
}

现在就已经完成了。重新启动项目,输入http://localhost:8080/ 还是刚才的用户名和密码,效果如下:

 接下来,我们来实现spring security的自定义认证。先修改下securityCOnfig类,

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserDetailsServiceImpl myUserDetailsService;

    //用户信息加解密,单向不可逆
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //在这里配置url访问权限,admin需要有admin授权,user则是有admin,user,一个角色即可访问
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests()
                .antMatchers("/user").hasAnyRole("USER", "ADMIN")
                .antMatchers("/admin").hasAuthority("ROLE_ADMIN")
                .anyRequest().permitAll()
                .and().formLogin()
                //启动http基础验证
                .and().httpBasic();
    }

    /*
     * 该方法是一个配置用户信息的方法,
     * 使用内存签名服务,数据库签名服务和自定义签名服务
     * 通过configure(HTTPSecurity httpSecurity)方法限定请求权限
     * */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //密码编码器
        PasswordEncoder passwordEncoder = passwordEncoder();
        auth.userDetailsService(myUserDetailsService)
                .passwordEncoder(passwordEncoder);
    }
}

 

添加UserDO,和UserRoleDO

public class UserDO {
    private Long id;

    private String userName;

    private String password;

    private Integer available;

    private String note;

    /*省去get,set访问*/
}



----------------------------------------------

public class UserRoleDO extends UserDO {
    private String roleName;

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
}

 

 添加UserDao(类似UserMapper),在src/main/resource/mybatis/下添加UserMapper.xml

@Mapper
public interface UserDao {
    List<UserDO> findAll();

    List<UserRoleDO> findRolesByUserName(String userName);

    UserDO getUserByName(String userName);
}


-------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.UserDao">

    <select id="findAll" resultType="com.example.demo.domain.UserDO">
        select * from t_user
    </select>

    <select id="findRolesByUserName" parameterType="String" resultType="com.example.demo.domain.UserRoleDO">
        select a.*, b.role_name from t_user a, t_role b, t_user_role c
        where a.user_name = #{userName} and a.id = c.user_id and b.id = c.role_id
    </select>

    <select id="getUserByName" resultType="com.example.demo.domain.UserDO" parameterType="String">
        select * from t_user where user_name = #{userName}
    </select>

</mapper>

然后添加UserService,UserServiceImpl

public interface UserService {
    List<UserDO> findAll();

    List<UserRoleDO> findRolesByUserName(String userName);

    UserDO getUserByName(String userName);
}



---------------------------------------------------
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public List<UserDO> findAll() {
        return userDao.findAll();
    }

    @Override
    public List<UserRoleDO> findRolesByUserName(String userName) {
        return userDao.findRolesByUserName(userName);
    }

    @Override
    public UserDO getUserByName(String userName) {
        return userDao.getUserByName(userName);
    }


}

UserController类如下:

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/hello")
    public Object hello() {
        return "hello";
    }

    @GetMapping("/user")
    public String user() {
        return "user";
    }

    @GetMapping("/admin")
    public String admin() {
        return "admin";
    }
}

 

 新建user.html, admin.html, hello.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>hello page</title>
</head>
<body>
<h1>你好,这里是hello 页面</h1>
<a href="/user">user</a>
<a href="/admin">admin</a>
</body>
</html>


--------------------------------------------------------------

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>admin</title>
</head>
<body>
<h1>hello,this is admin page, if you can see this page, you have admin role.</h1>
</body>
</html>


-----------------------------------------------------------------

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>user</title>
</head>
<body>
<h1>hello,this is user page, if you can see this page, you have user role.</h1>
</body>
</html>

UserDetailsServiceImpl 如下:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UserService userService;


    //获取用户信息,返回UserDetails接口对象,
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //获取数据库用户信息
        UserDO dbUser = userService.getUserByName(userName);
        System.out.println(dbUser.toString());
        //获取数据库角色信息
        List<UserRoleDO> roleList = userService.findRolesByUserName(userName);
        return changeToUser(dbUser, roleList);
    }

    private UserDetails changeToUser(UserDO dbUser, List<UserRoleDO> roleList) {
        //权限列表
        List<GrantedAuthority> authorityList = new ArrayList<>();

        //赋予查询到的角色
        for (UserRoleDO role : roleList) {
            GrantedAuthority authority = new SimpleGrantedAuthority(role.getRoleName());
            authorityList.add(authority);
        }
        //创建UserDetails对象,设置用户名、密码和权限
        return new org.springframework.security.core.userdetails.User(dbUser.getUserName(), dbUser.getPassword(), authorityList);
    }
}

配置文件application.properties如下:

spring.datasource.url=jdbc:mysql://localhost:3306/你的数据库名?serverTimezone=GMT%2B8
spring.datasource.username=用户名
spring.datasource.password=密码
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mybatis.configuration.map-underscore-to-camel-case=true
mybatis.mapper-locations=mybatis/**/*Mapper.xml
mybatis.type-aliases-package=com.example.demo.**.domain
logging.level.com.example.demo.dao=debug

spring.thymeleaf.encoding=UTF-8

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值