角色登录 - SpringSecurity框架实现用户登录校验角色

我们在企业级开发中, 用户只有在登录了账号才可以对表单中的数据进行相关的操作, 且不同身份角色的用户登录后对数据执行的权限也应该有所不同. 并且这些用户登录的账号不可以自己注册, 需要有权限的管理人员添加用户以及给该用户授予所具备的相关的权限. 下面我们先来实现用户登录后才可以操作数据的功能.

我们还是基于上一篇文章进行编写:https://blog.csdn.net/weixin_42629433/article/details/83342148

一. 在数据库中创建最高权限管理员

-- 用户表
CREATE TABLE users(
id INT(20) NOT NULL AUTO_INCREMENT,	
username VARCHAR(50),
PASSWORD VARCHAR(50),
phoneNum VARCHAR(20),
email VARCHAR(50),
STATUS INT,
PRIMARY KEY (id)		
)

INSERT INTO users VALUES (NULL, 'Zenith', '123456', '153********', '8123*****@qq.com',1);



-- 角色表
CREATE TABLE role(
id INT(20) NOT NULL AUTO_INCREMENT,
roleName VARCHAR(50) ,
roleDesc VARCHAR(50),
PRIMARY KEY (id)		
)

INSERT INTO role VALUES (NULL, 'Manager', '最高权限管理员');



-- 用户角色关联表
CREATE TABLE users_role(
userId VARCHAR(32),
roleId VARCHAR(32)
)

INSERT INTO users_role VALUES ('1', '1');

二. 相关文件配置

1. 导入 SpringSecurity 框架实现功能的相关依赖 :

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.0.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.0.1.RELEASE</version>
</dependency>

2. 在 web.xml 中引入 SpringSecurity 框架的配置 :

<!--Spring Security-->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

3. 在 resources 下创建 spring-security.xml 文件 :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- 配置不拦截的静态资源 -->
    <security:http pattern="/login.jsp" security="none"/>
    <security:http pattern="/failure.jsp" security="none"/>
    <security:http pattern="/css/**" security="none"/>
    <security:http pattern="/img/**" security="none"/>
    <security:http pattern="/plugins/**" security="none"/>

    <!--配置具体的规则:
        auto-config="true"	使用框架提供默认登录
        use-expressions="false"	是否使用SPEL表达式-->
    <security:http auto-config="true" use-expressions="false">
        <!-- 配置具体的拦截的规则 pattern="请求路径的规则" access="访问系统的人所具有的角色" -->
        <security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN,ROLE_MANAGER"/>
        <!-- 定义跳转的具体的页面 -->
        <security:form-login
        login-page="/login.jsp"
        login-processing-url="/login.do"
        default-target-url="/index.jsp"
        authentication-failure-url="/failure.jsp"
        authentication-success-forward-url="/pages/main.jsp"
        />
        <!-- 关闭跨域请求 -->
        <security:csrf disabled="true"/>
        <!-- 退出页面 -->
        <security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp" />
    </security:http>

    <!-- 切换成数据库中的用户名和密码 -->
    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userService">
            <!-- 配置加密的方式-->
            <security:password-encoder ref="passwordEncoder"/>
        </security:authentication-provider>
    </security:authentication-manager>

    <!-- 配置加密类 -->
    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

</beans>

4. 在 web.xml 中声明引入 spring-security.xml 文件至核心配置文件

<!--指定相关配置文件的路径-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml, classpath*:spring-security.xml</param-value>
</context-param>

 

三. 后台代码编写

1. 登录密码加密的工具类 :

package com.cast.domain;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.util.Scanner;

/**
 * 给密码加密的工具类
 */
public class BCryptPasswordEncoderUtils {

    private static BCryptPasswordEncoder bCryptPasswordEncoder=new BCryptPasswordEncoder();

    public static String encodePassword(String password){
        return bCryptPasswordEncoder.encode(password);
    }

    public static void main(String[] args) {
        System.out.println("请输入要加密的密码: ");
        Scanner input = new Scanner(System.in);
        String password = input.nextLine();
        String pwd = encodePassword(password);
        System.out.println("加密后的密码为: ");
        System.out.print(pwd);
    }

}

2. 在 service 层创建一个 IUserService 接口来继承 UserDetailsService 

package com.cast.service;

import org.springframework.security.core.userdetails.UserDetailsService;

public interface IUserService extends UserDetailsService {

}

3. 在 service 层创建一个 UserServiceImpl 类实现 IUserService 接口

package com.cast.service.impl;

import com.cast.dao.IUserDao;
import com.cast.domain.Role;
import com.cast.domain.UserInfo;
import com.cast.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
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.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {

    @Autowired
    private IUserDao userDao;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo userInfo = null;
        try {
            userInfo = userDao.findByUsername(username);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //将自己从数据库中查询到的Users对象封装到UserDetails中
        User user = new User(userInfo.getUsername(), userInfo.getPassword(), userInfo.getStatus() == 0 ? false : true, true, true, true, getAuthority(userInfo.getRoles()));
        return user;
    }

    //定义一个方法 将从数据库中获取到的所有角色装入集合
    public List<SimpleGrantedAuthority> getAuthority(List<Role> roles) {
        List<SimpleGrantedAuthority> list = new ArrayList<SimpleGrantedAuthority>();
        for (Role role : roles) {
            list.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
        }
        return list;
    }

}

4. 在 domain 子工程中声明 users role 的实体封装类 :

package com.cast.domain;

import java.util.List;

/**
 * 与数据库中 users 表对应
 */
public class UserInfo {

    private String id;
    private String username;
    private String password;
    private String phoneNum;
    private String email;
    private int status;
    private String statusStr;
    private List<Role> roles;

    public String getId() {
        return id;
    }

    public void setId(String 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 getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getStatusStr() {
        return statusStr;
    }

    public void setStatusStr(String statusStr) {
        this.statusStr = statusStr;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

}
package com.cast.domain;

import java.util.List;

/**
 * 与数据库中 role 表对应
 */
public class Role {

    private String id;
    private String roleName;
    private String roleDesc;
    private List<Permission> permissions;
    private List<UserInfo> users;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

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

    public String getRoleDesc() {
        return roleDesc;
    }

    public void setRoleDesc(String roleDesc) {
        this.roleDesc = roleDesc;
    }

    public List<Permission> getPermissions() {
        return permissions;
    }

    public void setPermissions(List<Permission> permissions) {
        this.permissions = permissions;
    }

    public List<UserInfo> getUsers() {
        return users;
    }

    public void setUsers(List<UserInfo> users) {
        this.users = users;
    }

}

5. 在 dao 层创建一个 IUserDao 接口

package com.cast.dao;

import com.cast.domain.UserInfo;
import org.apache.ibatis.annotations.*;

/**
 * 登录用户的 dao 层接口
 */
public interface IUserDao {

    //根据用户名查询用户
    @Select("select * from users where username = #{username}")
    @Results({
            @Result(id = true, property = "id", column = "id"),
            @Result(property = "username", column = "username"),
            @Result(property = "password", column = "password"),
            @Result(property = "phoneNum", column = "phoneNum"),
            @Result(property = "email", column = "email"),
            @Result(property = "status", column = "status"),
            @Result(property = "roles", column = "id", javaType = java.util.List.class,
                    many = @Many(select = "com.cast.dao.IRoleDao.findByUserId"))
    })
    public UserInfo findByUsername(String username) throws Exception;

}

6. 在 dao 层创建 IRoleDao

package com.cast.dao;

import com.cast.domain.Role;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * 用户的角色的 dao 层接口
 */
public interface IRoleDao {

    //根据用户id查询所有对应角色
    @Select("select * from role where id in (select roleId from users_role where userId = #{userId})")
    public List<Role> findByUserId(String userId) throws Exception;
    
}

三. 前台页面核心代码

1. login.jsp 登录界面的 form 表单 :

<form action="${pageContext.request.contextPath}/login.do" method="post">
    <div class="form-group has-feedback">
        <input type="text" name="username" class="form-control" placeholder="用户名">
        <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
    </div>
    <div class="form-group has-feedback">
        <input type="password" name="password" class="form-control" placeholder="密码">
        <span class="glyphicon glyphicon-lock form-control-feedback"></span>
    </div>
    <div class="row">
        <div class="col-xs-8">
            <div class="checkbox icheck">
                <label><input type="checkbox"> 记住 下次自动登录</label>
            </div>
        </div>
        <!-- /.col -->
        <div class="col-xs-4">
            <button type="submit" class="btn btn-primary btn-block btn-flat">登录</button>
        </div>
    <!-- /.col -->
    </div>
</form>

2. 登录失败后的 failure.jsp 页面提示返回到登录页面的超链接 :

<a href="${pageContext.request.contextPath}/login.jsp">返回到登录页面</a>

 

 

代码下载: https://pan.baidu.com/s/17zb834Qy1P5T3BiV7ivRig

***此代码需在 jdk1.8 下运行使用***

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值