程序员

Springboot+SpringSecurity不用模板引擎的登录功能

作者:admin 2021-06-09 我要评论

大家好这么久没更新文章是不是有点想我了呢 今天给大家带来的是SpringbootSpringSecurity在不使用模板引擎的情况下怎么做登录功能 Springboot官方是推荐使用模板...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

大家好,这么久没更新文章,是不是有点想我了呢?

今天给大家带来的是Springboot+SpringSecurity在不使用模板引擎的情况下,怎么做登录功能!

Springboot官方是推荐使用模板引擎的,百度上搜索SpringSecurity登录,大多数的都是使用模板引擎;

由于现在的项目大多都是前后端分离的,所以在开发中,大概率也不可能去使用模板引擎去写前端。

这个功能使用的是Springboot+SpringSecurity+Layui去实现的,有些急性子的同学看到这里,害Layui,我没用过,关闭,继续寻找下一个文章,

喂喂喂,大哥不要走啊,不会layui也可以的,你不要着急嘛!

你可以使用原生的html和jquery去实现,效果都是一样的,使用vue也完全可以啦~

好了,说了这么多"废话,下面开始代码展示"

使用的是maven工程,把这些依赖引入。Springboot的版本是2.x,如果引入依赖报错,就把版本号添加上

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

<dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
</dependency>

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
 </dependency>

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.3.1.tmp</version>
 </dependency>
<!--mysql驱动你可以根据自己的本地mysql版本选择,我这里使用的8.x,你可以使用5.x-->
<dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.20</version>
</dependency>

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.6</version>
</dependency>

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
</dependency>

下面是实体类,和数据库的表字段对应,直接去建数据库表就行,数据库我就不再贴了。

由于使用了lombok,则这个setter/getter方法就可以用@Data代替了,如果不想用,直接生成setter/getter方法也可以

@Data
@TableName(value = "tb_user")
public class Authority implements Serializable {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @TableField("username")
    private String username;
    @TableField("password")
    private String password;
    @TableField("phone")
    private String phone;
    @TableField("authority")
    private String authority;
}

然后是dao层,由于我们使用的是mybatis-plus,所以不需要自己写sql语句了,mybatis-plus也是兼容mybatis的,所以没用过的这个的小伙伴,写sql语句也是一样的

public interface AuthorityDao extends BaseMapper<Authority> {
}

对,你没有看错,就是这么简单,继承一下BaseMapper就可以了,迷惑的同学可以点开看一下源码,鼠标放BaseMapper上面 ctrl + 鼠标左键,里面都是封装好的方法

然后就是service层,这里的service更普通的service有点不一样了,哪里不一样呢,等下解释

public interface AuthorityService extends UserDetailsService {
}
@Slf4j
@Service
public class AuthorityServiceImpl implements AuthorityService {

// 注入dao层接口
    @Resource
    private AuthorityDao authorityDao;

// 重写UserDetailsService中的方法
    @Override
    public UserDetails loadUserByUsername(String username) {
        QueryWrapper<Authority>  qw = new QueryWrapper<>();
        qw.eq("username",username);
        Authority authority = authorityDao.selectOne(qw);
        if (null == authority) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        // 把用户名存入session,这里这个获取session的工具类,我也给大家放到下边
     // 存入session是方便获取到登录的用户名       
GetSessionUtils.getSession().setAttribute("loginUsername",authority.getUsername());
// 这个User是SpringSecurity提供的,而不是自己写的,只需要传入账号密码,和权限,SpringSecurity会自己判断账号密码,密码应该是加密过后的密码,而不是明文,如何得到密文,在文章末尾我会给出
        return new User(authority.getUsername(),authority.getPassword(),getAuthority());
    }
// 指定一个权限,拥有该权限的才能登录
// 数据库里边存的是 ADMIN,并不是 ROLE_ADMIN
    private List<GrantedAuthority> getAuthority() {
        return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
    }
}
public class GetSessionUtils {
    private GetSessionUtils(){}

    public static HttpSession getSession() {
        ServletRequestAttributes attributes
                = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        return request.getSession();
    }

}

?

我选择了使用一个接口去继承UserDetailsService,然后再实现,以便以后的方法的扩充,当然也可以直接实现UserDetailsService

controller层,这个控制层还是要写的

@Slf4j
@Controller
public class AuthorityController {

    @GetMapping("/user/login/success")
    @ResponseBody
    public Msg loginSuccess() {
        return Msg.success();
    }

    @GetMapping("/user/login/fail")
    @ResponseBody
    public Msg loginFail() {
        return Msg.fail();
    }

    /**
     * 获取登录用户名
     */
    @GetMapping("/user/getUsername")
    @ResponseBody
    public Msg getUserName(HttpServletRequest request) {
        return Msg.success().add("msg",request.getSession().getAttribute("loginUsername"));
    }

}

Msg是统一的返回格式,代码如下

@Data
public class Msg implements Serializable {
    private String msg;
    private Integer code;
    Map<String,Object> extend = new HashMap<>();

    public static Msg success() {
        Msg result = new Msg();
        result.setMsg("处理成功");
        result.setCode(200);
        return result;
    }

    public static Msg fail() {
        Msg result = new Msg();
        result.setCode(100);
        result.setMsg("处理失败");
        return result;
    }

    public Msg add(String key, Object value) {
        this.extend.put(key, value);
        return this;
    }
}

?

然后到了关键的配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(getPassword());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
            // 指定前端input字段的名字,即name,不指定默认为username和password
                .passwordParameter("username")
                .passwordParameter("password")
                // 自定义登录界面的地址
                .loginPage("/login.html")
                // 登录请求的处理的url,即ajax的url地址
                .loginProcessingUrl("/user/login")
                // 登录失败之后的处理接口,你也可以自定义handler处理
                .failureUrl("/user/login/fail")
            // 登录成功后默认的请求接口(contoller中的接口)
                .defaultSuccessUrl("/user/login/success")
                .and().authorizeRequests()
                // 设置 user/login/** 接口谁都可以访问,否则没办法登录
                .antMatchers("/user/login/**").permitAll()
            //   拥有ADMIN的权限,可以肆意妄为,什么操作都能做
                .antMatchers("/**").hasAnyRole("ADMIN")
                .and().httpBasic()
                // 跨域保护禁用掉
                .and().csrf().disable();
//        关闭禁用frame框架,不关闭的话,不允许嵌套页面的出现,这个地方困扰了我很久
        http.headers().frameOptions().disable();
//         退出登录的接口地址,以及退出登录之后,返回到哪个页面
        http.logout().logoutUrl("/user/logout").logoutSuccessUrl("/login.html");

    }

    @Bean
    HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
       // 密码加密
    @Bean
    public BCryptPasswordEncoder getPassword() {
        return new BCryptPasswordEncoder();
    }
    // 静态资源的放行规则,放行所有静态资源,并且放行登录页面
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**","/img/**",
                "/js/**","/layui/**","/login.html");
    }

}

上面的配置类的注释,我给大家补全了,相信大家能看懂,看不懂就留言,我回复的很及时

然后就是启动类

@EnableTransactionManagement
@EnableScheduling
@EnableCaching
// 这个地方是扫描多个dao包,如果只有一个dao包,就用没有注释的注解
// @MapperScan({"包1","包2"})
@MapperScan("自己的包名字")
@SpringBootApplication
// 开启SpringSecurity的支持
@EnableWebSecurity
// 开启全局SpringSecurity方法
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true,jsr250Enabled = true)
public class PrisonSystemApplication {

    public static void main(String[] args) {
        SpringApplication.run(PrisonSystemApplication.class, args);
    }

}

properties的配置文件我也给大家贴上吧,免得大家在去别的地方找;5.x的数据库,去掉第一行的cj即可,大家注意修改一下

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/login?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

#禁用缓存
spring.thymeleaf.cache=false
#配置要扫描的包(pojo)
mybatis.type-aliases-package=填写实体类的包位置
#开启Restful风格的支持
spring.mvc.hiddenmethod.filter.enabled=true

登录界面 (login.html),这个大家可以去网上找一个,或者自己写一个简单的登录页面,这个地方我引入了一些外部的样式。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link rel="stylesheet" href="layui/css/layui.css">
    <link rel="stylesheet" href="css/adminLogin.css">
    <script src="layui/layui.js"></script>
</head>
<body style="background: url(img/1.jpg);">
<div class="wrap">
    <div class="loginForm">
        <form id="loginFormSubmit">
            <div class="logoHead">
            </div>
            <div class="usernameWrapDiv">
                <div class="usernameLabel">
                    <label>用户名:</label>
                </div>
                <div class="usernameDiv">
                    <i class="layui-icon layui-icon-username adminIcon"></i>
                    <input id="loginUsername" class="layui-input adminInput" type="text" name="username" placeholder="输入用户名" >
                </div>
            </div>
            <div class="usernameWrapDiv">
                <div class="usernameLabel">
                    <label>密码:</label>
                </div>
                <div class="passwordDiv">
                    <i class="layui-icon layui-icon-password adminIcon"></i>
                    <input id="loginPassword" class="layui-input adminInput" type="password" name="password" placeholder="输入密码">
                </div>
            </div>
            <br/>

            <div class="usernameWrapDiv">
                <div class="submitDiv">
                    <input id="loginBtn" type="button" class="submit layui-btn layui-btn-primary" lay-submit lay-filter="login-submit" value="登录"/>
                </div>
            </div>
        </form>

    </div>
</div>

</body>
<script>

    layui.use(['form', 'jquery'], function () {
        var $ = layui.jquery;
        var form = layui.form;
        //登录提交
        form.on('submit(login-submit)', function () {
            $.ajax({
            // 此处为配置类的登录处理接口
                url:"/user/login",
            // 提交方法必须是post
                method:'post',
            // 将整个form表单序列化,提交到后端
                data:$("#loginFormSubmit").serialize(),
                success:function (msg) {
            // 状态码为 Msg类自定义的,当然你可以随意改动
                    if (msg.code == 100) {
                        layer.alert('账号或密码错误,请重试', {
                            icon: 5,
                            title: "提示"
                        });
                    }else {
                    // 登录成功后要跳转到的页面
                        window.location.href = "index.html"
                    }
                },
                error:function (err) {
                    console.log(err)
             // 如果网页有图片没有,请删除或注释掉引入图片的代码,否则第一次点击会出现这个提示
                    layer.alert('发生了未知的错误,请联系管理员解决', {
                        icon: 5,
                        title: "提示"
                    });
                }
            });
        });
    });
</script>
</html>

css

/*登陆表单样式 start*/
		.wrap{
		    width: 100%;
		    height: 100%;
		    /*background: url("../images/back.jpg") no-repeat;*/
		    background-size: cover;
		}
		.loginForm{
		    margin-left: 35%;
		    margin-top: 10%;
		    /*background-color: #cccccc;*/
		    background-color: #e7e7e7;
		    width: 400px;
		    height: 400px;
		    float: left;
		    z-index: 9999;
		    position: fixed;
		    opacity: 0.75;
		}
		.usernameDiv{
		    width: 300px;
		    height: 40px;
		    padding-left: 130px;
		    padding-top: 30px;
		
		}
		.adminInput{
		    width: 200px;
		    height: 40px;
		    font-size: 15px;
		    border-radius: 0.5em;
		    /*margin-left: auto;*/
		    /*border: 1px solid #cccccc;*/
		}
		.passwordDiv{
		    width: 300px;
		    height: 40px;
		    padding-left: 130px;
		    padding-top: 28px;
		}
		.cardDiv{
		    width: 120px;
		    height: 40px;
		    padding-top: 28px;
		    padding-left: 14px;
		    float: left;
		}
		.cardInput{
		    width: 124px;
		    height: 40px;
		    font-size: 15px;
		    border-radius: 0.5em 0em 0em 0.5em;
		}
		.codeDiv{
		    width: 100px;
		    height: 40px;
		    padding-top: 28px;
		    padding-right: 20px;
		    float: left;
		}
		.codeInput{
		    width: 80px;
		    height: 40px;
		    font-size: 15px;
		    border-radius: 0em 0.5em 0.5em 0em;
		    /*验证码样式*/
		    font-family: Arial;
		    font-style: italic;
		    font-weight: bold;
		    /*border: 0;*/
		    letter-spacing: 2px;
		    cursor: pointer;
		}
		i{
		    position: absolute;
		}
		.adminIcon{
		    font-size: 22px;
		    margin-top: 8px;
		    margin-left: 165px;
		}
		.logoHead{
		    width: 250px;
		    height: 60px;
		    padding-left: 90px;
		    padding-top: 25px;
		}
		.usernameLabel{
		    width: 60px;
		    height: 30px;
		    font-size: 16px;
		    float: left;
		    margin-left: 55px;
		    margin-top: 40px;
		}
		.submitLabel{
		    width: 160px;
		    height: 30px;
		    font-size: 13px;
		    float: left;
		    margin-left: 55px;
		    margin-top: 40px;
		    cursor: pointer;
		}
		.usernameWrapDiv{
		    width: 400px;
		    height: 70px;
		}
		.submitDiv{
		    width: 150px;
		    height: 40px;
		    padding-left: 10px;
		    padding-top: 28px;
		    float: left;
		}
		.submit{
		    width: 100px;
		    height: 40px;
		    border-radius: 0.5em;
		}
		img{
		    position: absolute;
		}
		.imgStyle{
		    width: 100%;
		    height: 100%;
		}
		/*登陆表单样式 end*/
		
		/*注册页面样式 start*/
		.registerPage{
		    width: 100%;
		    height: 100%;
		    /*background-color: #cccccc;*/
		    display: none;
		    opacity: 0.75;
		}
		.registerDiv{
		    width: 100%;
		    height: 100%;
		    z-index: 9999;
		    opacity: 0.75;
		}

layui.js你可以使用jquery代替,我只不过是为了好看而已,而且大家是后端,暂时也没有必要去研究样式

注意:不能有不存在的图片链接,否则可以出现点击一次登录不成功的bug

?

平时大家做的登录,都会先经过控制层,而SpringSecurity则不会,你把提交的接口改为和配置类处理的接口相同,它就会自动的去执行Service层的loadUserByUsername方法,然后就是判断规则,注意密码,上面给大家提到了怎么存密文,如下面的代码,就能得到一个密文串,当然如果大家要注册功能的话,只需要在注册提交之后,在后端拿到明文密码再加密,最后存储即可。

?

public class BCTest {
    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        System.out.println(bCryptPasswordEncoder.encode("123"));
    }
}

登录失败效果展示(登录成功会跳转到指定的页面,就不在展示了):

密码输入错误,会有提示框,你也可以加汉字,在controller层返回的时候,在原有的返回代码后加?.add(key,value); 然后通过msg.extend.key 拿到value,填充到你想要指定的位置即可

?

好了,这篇文章就到这里啦,大家有什么问题,可以在下方留言,有什么错误的地方,欢迎指出。如果文章对你有帮助,请点个赞点个关注留下你的足迹吧!

?

?

;原文链接:https://blog.csdn.net/weixin_44231805/article/details/115563895

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 第 2 章 基本数据类型

    第 2 章 基本数据类型

  • LeetCode笔记:Weekly Contest 234 比

    LeetCode笔记:Weekly Contest 234 比

  • 2021-04-11

    2021-04-11

  • 字符串算法 |   AC自动机算法

    字符串算法 | AC自动机算法

腾讯云代理商
海外云服务器