大家好,這么久沒更新文章,是不是有點想我了呢?
今天給大家帶來的是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://www.uj5u.com/ruanti/274769.html
標籤:其他
上一篇:springcloud Alibaba 阿里組件 nacos注冊中心 gateway網關 flowable流程引擎 vue.js前后分離
下一篇:C++ list類的模擬實作
