springBoot和security实现不同用户登录

通过访问数据库,实现不同用户、不同角色登录系统。

以简单的表结构演示案例。

一  创建数据表

角色表   (role):

用户表 (user):

用户角色关系表(user_role):

二  搭建项目结构

三 编码实现

1)yml配置文件

server:
  servlet:
    context-path: /zmd
mybatis:
  type-aliases-package: com.zmd.pojo  # 批量设置别名
  mapper-locations: classpath:com/zmd/mapper/*.xml  # 设置mapper的路径
  configuration:
    auto-mapping-behavior: full # 设置全自动映射
    use-column-label: true # 设置别名可以做列名
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    username: root
    password: 123456
  thymeleaf:
    cache: false
    suffix: .html
  jackson:
    # 如果使用字符串星表示用这行格式
    date-format: yyyy-MM-dd
    # 设置为东八区时间
    timezone: GMT+8
    # 想要值为2016-01-01
    serialization:
      write-dates-as-timestamps: false
# 显示SQL语句
logging:
  level:
    com:
      zmd:
        mapper: debug

2)实体类(pojo)

user:

@Data
public class User {
    private Integer id;
    private String name;
    private String password;
    private List<Role> roles=new ArrayList<>();
}

role:

扫描二维码关注公众号,回复: 16661253 查看本文章
@Data
public class Role {
    private Integer id;
    private String name;
    private List<User> users = new ArrayList<User>();
}

3)mapper

<?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.zmd.mapper.UserMapper">

    <select id="getUser" resultMap="roleList">
        select  r.id, r.name,u.id uid,u.name uname,u.password from role r left join user_role ur
        on ur.rid=r.id
        LEFT JOIN user u
        on u.id=ur.uid
        where u.name=#{name}
</select>
    <!--根据用户的id查询这个用户的所有的角色-->
    <resultMap id="roleList" type="user" autoMapping="true">
        <id column="uid" property="id"></id>
        <result property="name" column="uname"></result>
        <collection property="roles" ofType="role" autoMapping="true">
            <id column="id" property="id"></id>
        </collection>
    </resultMap>
</mapper>

在启动类中配置扫描:


@SpringBootApplication
@MapperScan("com.zmd.mapper")
public class Security1902Application {
    public static void main(String[] args) {
        SpringApplication.run(Security1902Application.class, args);
    }

4)service业务

通过重写方法,从当前登录账号对应的数据库数据中获取到账号角色等信息。


@Service
public class UserDetailsServiceImpl  implements UserDetailsService {
    @Resource
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        User user = userMapper.getUser(username);
        System.out.println("service来了");
        if (user == null) {
            System.out.println("该用户不存在");
        } else {
            List<Role> roles = user.getRoles();
            for (Role r : roles) {
                System.out.println("角色:"+r.getName());
                authorities.add(new SimpleGrantedAuthority(r.getName()));
            }
            org.springframework.security.core.userdetails.User u = new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(), authorities);
            System.out.println("u:"+u);
            return u;
        }
        return null;
    }
}

5)配置类WebSecurityConfig


@Configuration
@EnableWebSecurity //启动安全框架
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启注解级别方法权限控制
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin()  //指定支持基于表单的身份验证
                .loginPage("/login") //默认的登录路径
                .loginProcessingUrl("/loginCheck")//登录页面提交的路径,需要和页面的路径保持一致
                .defaultSuccessUrl("/logSuccess")//登录成功后跳转的路径
                .failureUrl("/error2")//登录失败后跳转的路径
                .usernameParameter("username")//获取页面的配置的用户名,和页面的值保持一致
                .passwordParameter("password")
                .permitAll()//路径不设权限
                .and()
                .csrf().disable();//阻止跨域请求伪造攻击

    }
    //用于对比密码
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return s.equals(charSequence.toString());
            }
        });
    }

    //静态请求要放行
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/webjars/**").antMatchers("/static/**");
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }


}

6)controller


@Controller
public class MyController {

    @RequestMapping("/login")
    public String login(){
        System.out.println("这是login。。。");
        return "login";
    }
    @RequestMapping("/logSuccess")
    public String logSuccess(){
        System.out.println("登录成功");
        return "index";
    }

    @RequestMapping("/error2")
    @PreAuthorize("hasAnyAuthority('admin','user')")
    public String error111(){
        return "error1";
    }


}

7)登录页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录界面</title>
    <script type="text/javascript" th:src="@{/webjars/jquery/3.3.1/jquery.js}"></script>
    <script type="text/javascript" th:src="@{/webjars/layui/2.5.6/layui.js}" ></script>
    <link rel="stylesheet"  th:href="@{/webjars/layui/2.5.6/css/layui.css}" />
    <style type="text/css">
        .container{
            width: 420px;
            height: 320px;
            min-height: 320px;
            max-height: 320px;
            position: absolute;
            top: 0;
            left: 0;
            bottom: 0;
            right: 0;
            margin: auto;
            padding: 20px;
            z-index: 130;
            border-radius: 8px;
            background-color: #fff;
            box-shadow: 0 3px 18px rgba(100, 0, 0, .5);
            font-size: 16px;
        }
        .close{
            background-color: white;
            border: none;
            font-size: 18px;
            margin-left: 410px;
            margin-top: -10px;
        }

        .layui-input{
            border-radius: 5px;
            width: 300px;
            height: 40px;
            font-size: 15px;
        }
        .layui-form-item{
            margin-left: -20px;
        }
        #logoid{
            margin-top: -16px;
            padding-left:150px;
            padding-bottom: 15px;
        }
        .layui-btn{
            margin-left: -50px;
            border-radius: 5px;
            width: 350px;
            height: 40px;
            font-size: 15px;
        }
        .verity{
            width: 120px;
        }
        .font-set{
            font-size: 13px;
            text-decoration: none;
            margin-left: 120px;
        }
        a:hover{
            text-decoration: underline;
        }
    </style>
</head>
<body>
<!-- 注意此处提交的路径-->
<form class="layui-form" th:action="@{/loginCheck}" method="post">
    <div class="container">
        <button class="close" title="关闭">X</button>
        <div class="layui-form-mid layui-word-aux">
            <img id="logoid" src="" height="35">
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">用户名</label>
            <div class="layui-input-block">
                <input type="text" name="username" required  lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">密 &nbsp;&nbsp;码</label>
            <div class="layui-input-inline">
                <input type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
            </div>
            <!-- <div class="layui-form-mid layui-word-aux">辅助文字</div> -->
        </div>

        <div class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn" lay-submit lay-filter="formDemo">登陆</button>
            </div>
            <div class="layui-input-block">
                <button type="reset" class="layui-btn layui-btn-warm">重置</button>
            </div>
        </div>
        <a href="" class="font-set">忘记密码?</a>  <a href="" class="font-set">立即注册</a>
    </div>
</form>
</body>
</html>

四  运行测试

1)错误账号密码登录:

登录失败,不会进行跳转。

2)登录成功

观察控制台:

小结

通过上述步骤,实现了用户登录。

该用户的账号和密码必须匹配数据表中数据,并且可以成功获取到该账号对应的角色,

以方便后续进行权限的相关处理。

欢迎留言评论,交流学习。

猜你喜欢

转载自blog.csdn.net/woshishq1210/article/details/117804174