您的位置:首页 > 编程语言 > Java开发

在SpringBoot项目中使用SpringSecurity权限认证框架

2017-12-21 15:28 1051 查看
当前两大权限认证框架:shiro和Spring Security
SpringBoot版本:1.5.8

1.在SpringBoot中欲使用Spring Security,首先需要添加依赖:

<!--声明使用Spring security的依赖-->

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

</dependency>

<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>

</dependency>
2.在Application的Properties文件中,配置:

#Spring Security config

logging.level.org.springframework.security=info
3.写一个Security的Java配置类:

package com.kgoos.app.configure;
import
org.springframework.context.annotation.Bean;
import
org.springframework.context.annotation.Configuration;
import
org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import
org.springframework.security.core.userdetails.UserDetailsService;
@Configuration
public class
WebSecurityConfig extends
WebSecurityConfigurerAdapter {
@Bean
UserDetailsService customUserService() {
//2
return new
SysUserServiceImpl();
}
@Override
protected void
configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(customUserService());
}
@Override
protected void
configure(HttpSecurity http) throws
Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.permitAll()
.and()
.logout().permitAll();
}
}
在SpringMVC中也添加配置:

@Configuration
public class
MyWebConfig extends
WebMvcConfigurerAdapter {
@Override
public void
addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
4.准备SpringSecurity认证需要的两个实体类:SysRole和SysUser

import lombok.Getter;
import
lombok.Setter;
import
javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.Id;
import
java.io.Serializable;
/**
* Description:This PO is used for system auth :Spring Security
*
@author
dbdu
*
@date
17-12-21 上午9:34
*/
@Entity
@Getter@Setter
public class
SysRole implements
Serializable { //注意此处要实现序列化接口,否则终端执行会出错!
@Id
@GeneratedValue
private
Long id;
private
String name;

}
------------------------------------------

import java.util.ArrayList;

import java.util.Collection;

import java.util.List;
import
javax.persistence.CascadeType;
import
javax.persistence.Entity;
import
javax.persistence.FetchType;
import
javax.persistence.GeneratedValue;
import
javax.persistence.Id;
import
javax.persistence.ManyToMany;
import
lombok.Getter;
import
lombok.Setter;
import
org.springframework.security.core.GrantedAuthority;
import
org.springframework.security.core.authority.SimpleGrantedAuthority;
import
org.springframework.security.core.userdetails.UserDetails;

@Entity
@Getter@Setter
public class
SysUser
implements
UserDetails { //1
private static final long
serialVersionUID
= 1L;
@Id
@GeneratedValue
private
Long id;
private
String username;
private
String password; //当然若是实际项目中使用,可能会有其他更多的属性.
@ManyToMany(cascade = {CascadeType.REFRESH},
fetch = FetchType.EAGER)
private
List<SysRole> roles;
@Override
public
Collection<? extends
GrantedAuthority> getAuthorities() {
//2
List<GrantedAuthority> auths =
new ArrayList<GrantedAuthority>();
List<SysRole> roles =
this.getRoles();
for
(SysRole role : roles) {
auths.add(new
SimpleGrantedAuthority(role.getName()));
}
return
auths;
}
@Override
public boolean
isAccountNonExpired() {
return true;
}
@Override
public boolean
isAccountNonLocked() {
return true;
}
@Override
public boolean
isCredentialsNonExpired() {
return true;
}
@Override
public boolean
isEnabled() {
return true;
}

}
5.准备实体对应的repository和Service

import com.kgoos.app.entity.SysUser;

import org.springframework.data.jpa.repository.JpaRepository;

public interface
SysUserRepository
extends
JpaRepository<SysUser, Long> {
SysUser findByUsername(String username);

}

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

import com.kgoos.app.entity.SysUser;
import
com.kgoos.app.repository.SysUserRepository;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.security.core.userdetails.UserDetails;
import
org.springframework.security.core.userdetails.UserDetailsService;
import
org.springframework.security.core.userdetails.UsernameNotFoundException;
@Service
public class
SysUserServiceImpl implements
ISysUserService { //1
@Autowired
SysUserRepository
userRepository;
@Override
public
UserDetails loadUserByUsername(String username) {
//2
SysUser user =
userRepository.findByUsername(username);
if(user ==
null){
throw new
UsernameNotFoundException("用户名不存在");
}
return
user; //3
}
}

/**
* Description:此处继承仅是为了让代码看起来更加规范而已
* Created at:2017-12-21 10:12,
* by dbdu
*/
public interface
ISysUserService extends
UserDetailsService {}
6.向数据表中插入基本的数据:

insert into SYS_USER (id,username, password) values (1,'dbdu', 'dbdu');

insert into SYS_USER (id,username, password) values (2,'dusuanyun', 'dusuanyun');

insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN');

insert into SYS_ROLE(id,name) values(2,'ROLE_USER');

insert into SYS_USER_ROLES(SYS_USER_ID,ROLES_ID) values(1,1);

insert into SYS_USER_ROLES(SYS_USER_ID,ROLES_ID) values(2,2);
7.注意login和logout的url是固定的,为/login和/logout,不需要专门为这两个url写控制器!!

8.准备login.html和home.html的thymeleaf文件放置在,resources--templates目录下.

9.详细信息,参考KGoos项目的security_test_branch分支,此分支配置了此框架的认证方式.

疑问1:如何根据角色不同,区分什么是admin的,什么是普通用户的?
解答:

方式一:使用thymeleaf有方式可以判断角色

A.先引入命名空间:<html
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

B.使用hasRole('ROLE_ADMIN')"来判断角色:

<div
sec:authorize="hasRole('ROLE_ADMIN')">

<p
class="bg-info"
th:text="${msg.etraInfo}"></p>

</div>

方式二:使用异步Ajax的方式

如果前端需要角色信息来决定显示什么页面,可以考虑提供控制器将用户信息以Json的方式给前端!
疑问2:如何添加用户?

解决:利用Hibernate的映射关系存储关联关系!
疑问3:如何使用密码的密文? ---现在存储的是明文

解决:

第一步:自己定义一个密码编码解码的类实现PasswordEncoder接口

/**
* Description: 这个类是专为使用SpringSecurity认证框架设计的,用户处理密码是明码还是密码的问题!
* Created at:2017-12-21 14:18,
* by dbdu
*/
public class
MD5PasswordEncoder implements
PasswordEncoder {
@Override
public
String encode(CharSequence charSequence) {
return
MD5Util.encode((String) charSequence);
}
@Override
public boolean
matches(CharSequence rawPassword, String encodedPassword) {
if
(null
!= encodedPassword && encodedPassword.equals(encode(rawPassword))) {
return true;
}
return false;
}
}

第二步:在WebSecurityConfig类中,增加自定义的编码解码器,例如:

@Configuration
public class
WebSecurityConfig extends
WebSecurityConfigurerAdapter {
@Bean
UserDetailsService customUserService() {
//2
return new
SysUserServiceImpl();
}
@Override
protected void
configure(AuthenticationManagerBuilder auth)
throws Exception {
//指定密码的编码和解码方式:MD5PasswordEncoder
auth.userDetailsService(customUserService()).passwordEncoder(new
MD5PasswordEncoder());

//auth.userDetailsService(sysUserService);
}
@Override
protected void
configure(HttpSecurity http)
throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.permitAll()
.and()
.logout().permitAll();
}
}
疑问4:如何将登录的用户,用户名显示在页面上,其实就是如何获取已经登录成功的用户的信息
解决:没有测试过

A.JSP的方式:principal 用户的基本信息对象



B.Thymeleaf的方式:

方式一:使用表达式实用程序对象

该#authentication对象可以很容易地使用,就像这样:
<
div
th:text
= “ $ {#authentication.name} ” > 认证对象的“name”属性的值应该出现在这里。 </
div >

方式二:使用sec:authentication属性相当于使用#authentication对象,但使用自己的属性:
<
div
sec:authentication
= “ name ” > 认证对象的“name”属性的值应该出现在这里。 </
div >

更多的内容参见:https://github.com/thymeleaf/thymeleaf-extras-springsecurity
英语不好的朋友可以用谷歌浏览器右键翻译

C.自己的思路:

登录成功后,发请求,然后将请求到的数据直接存到session会话里,写一个监听器session注销的时候,清除保存在session里的数据,当然你要是不管它好像也没什么问题.

参考资料:
A.<<JavaEE开发的颠覆者-SpringBoot实战>>,第九章第一节
B.<<Spring实战第四版中文版>>,第九章
C.参考链接:https://github.com/thymeleaf/thymeleaf-extras-springsecurity
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐